疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java集合 Java核心技术读书笔记


 

1.Collection接口
2.迭代器
public interface Iterator<E>{
E next();
boolean hasNext();
void remove();
}
善用迭代器
Collection<String> c = ...;
Iterator<String> iter = c.iterator();
while(iter.hasNext()){
String element = iter.next();
do something with element
}
 
还有“for each”循环:
for(String element:c){
do something with element
}
3.删除元素
Iterator接口的remove方法将会删除上次调用next方法时返回的元素。如删除字符串集合中的第一个元素:
Iterator<String> iter = c.iterator();
iter.next();
iter.remove();
注意:对next方法和remvoe方法的调用具有互相依赖性。如果调用remvoe之前没有调用next将是不合法的,会抛出IlleStateException异常。
如果想删除两个相邻的元素,不能直接这样调用:
iter.remove();
iter.remove();
必须先调用next越过将要删除的元素。
iter.next();
iter.remove();
iter.next();
iter.remove();
4.善用collection接口提供的方法,如:
int size();
boolean isEmpty();
boolean contains(Object o);
boolean containsAll(Collection<?> c);
boolean equals(Object o);
boolean addAll(Collection<? extends E> c);
boolean remove(Object o);
boolean removeAll(Collection<?> c);
void clear();
boolean retainAll(Collection<?> c);
Object[] toArray();
<T> T[] toArray(T[] a);
5以Map结尾的类实现了Map接口,其他类则实现了Collection接口
 
6.链表
数组和数组列表有一个重大缺陷:从中间位置删除或插入一个元素要付出很大的代价,而链表解决了这个问题。在Java程序设计语言中,所有的链表都是双向链接的,即每个结点还存放着指向前驱结点的引用。
List<String> staff = new LinkedList<String>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
staff.remove("Amy");
可以使用ListIterator向.链表新增元素:
List<String> staff = new LinkedList<String>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
ListIterator<String> iter = staff.listIterator();
iter.next();
iter.add("Juliet");
iter.next();
iter.remove();
使用“光标”进行元素的增删时一定要注意“光标”位置
注意:如果在某个迭代器修改集合时,另一个迭代器对其进行遍历,会出现混乱状况,将抛出 ConcurrentModificationException异常。如
List<String> staff = ... ;
Iterator<String> iter1 = staff.iterator();
Iterator<String> iter2 = staff.iterator();
iter1.next();
iter1.remove();
iter2.next(); // 抛出ConcurrentModificationException异常
 
可以根据需要同时给窗口附加许多迭代器,但这些迭代器只能读取列表。另外,单独附加一个既能读又能写的迭代器。
LinkedList类提供了用来访问某个特定元素的get方法:
LinkedList<String> list = ...;
String obj = list.get(n);
但这种方法效率并不太高,如果发现自己正在使用这个方法,说明 有可能对于所要解决的问题使用了错误的数据结构。
绝对不能使用下面这种方法遍历链表,它的效率极低。
for(int i = 0; i < list.size(); i++)
do something with list.get(i);
优先使用链表,但避免使用以整数索引表示链表中位置的所有方法。如果需要对集合进行随机访问,就使用数组或ArrayList,而不要使用链表。
 
7.散列集Set
使用散列集存放自定义的类时,就是要负责实现这个类的hashCode方法。注意:自己实现的hashCode要与equals方法兼容,即如果a.equals(b)为true,a与b必须具有相同 的散列码。
8.树集
TreeSet类是 一个有序集合。每次将一个元素添加到树中,都被放置在正确的排序位置上。因此迭代器总是以排好序的顺序访问每个元素。(当前实现使用的红黑树)
将一个元素添加到树中要比添加到散列表中慢,但是,与将元素添加到数组或链表的正确位置上相比还是快很多。
可以将Comparator对象传递给TreeSet构造器来告诉树集使用的比较方法。如:
class ItemComparator implements Comparator<Item>{
public int compare(Item a,Item b){
String descrA = a.getDescription();
String descrB = b.getDescription();
return descrA.compareTo(descrB);
}
}
 
然后将这个类的对象传递给树集的构造器:
ItemComparator comp = new ItemComparator();
SortedSet<Item> sortByDescription = new TreeSet<Item>(comp);
注意:Comparator这个比较器没有任何数据。它只是比较方法的持有器。有时将这种对象称为函数对象。函数对象通常被定义为“瞬时的”,那使用匿名内部类实现。
SortedSet<Item> sortByDescription = new TreeSet<Item>(new 
Comparator<Item>{
public int compare(Item a,Item b){
String descrA = a.getDescription();
String descrB = b.getDescription();
return descrA.compareTo(descrB);
}
});
 
9.优先级队列并没有对所有的元素进行排序,而是使用了堆。堆是一个可以自我调整的二叉树,对树执行添加和删除操作,可以让最小的元素移动到根,而不必花费时间对元素进行排序。
10.映射表Map有三个视图:
Set<K> keySet()
Collection<K> values()
set<Map.Entry<K,V>> entrySet()
注意:keySet既不是HashSet,也不是TreeSet,而是实现了Set接口的某个其他类。Set接口扩展了Collection接口,因此可以与使用任何集合一样使用keySet。
可以调用迭代器的remove方法从眏射表中删除键以及对应的值。但是不能将元素添加到键集的视图中。如:
Set<String> keys = map.keySet();
Iterator<String> iter = keys.iterator();
iter.next();
iter.remove();
 
11.只有可以随机访问的容器,如ArrayList,二分查找。如果必须利用迭代方式一次次地遍历链表的一半元素找到中间位置的元素,二分查找就完全失去了优势了。因此,如果为binarySearch算法提供一个链表,它将自动变为线性查找。