一.集合的接口
java集合类库也将接口与实现相分离。首先看一下大家都熟悉的数据结构-队列是如何分离的。队列接口指出可以在队列的尾部添加元素,在队列的头部删除元素,并且可以查找队列中元素的个数。当需要收集对象,并按照“先进先出”的规则检索对象时就应该使用队列。
队列通常有两种实现方式:循环数组 和 链表。循环数组查询数据的效率比链表高,但是增加和删除元素的速度没链表快。并且循环数组是一个有界集合,即容量有限,如果程序中要收集的对象数量没有上限,就最好使用链表来实现。
在Java类库中,集合类的基本接口是Collection接口,这个接口有两个基本方法:
1 public interface Collection<E> 2 { 3 boolean add(E element); 4 Iterator<E> iterator(); 5 ... 6 }
add方法用于往集合中添加元素。如果添加元素确实改变了集合就返回true,如果集合没有改变就返回false。注意,如果视图往集中添加一个元素,而这个对象在集中已经存在,这个添加请求就没有实效,因为集中不允许有重复的对象,返回false。
iterator方法用于返回一个实现了Iterator接口的对象。可以使用迭代器依次访问集合中的元素。
1.迭代器
Iterator接口包含3个方法:
1 public interface Iterator<E> 2 { 3 E next(); 4 boolean hasNext(); 5 void remove(); 6 }
通过反复调用next方法,可以逐个访问集合中的每个元素。但是如果达到了集合的末尾,next方法将会抛出一个NoSuchElementException。因此在调用next之前调用hasNext方法。
元素被访问的顺序取决于集合类型。如果对ArrayList等有序集合迭代,迭代器将从索引0开始,依次往下。如果访问HashSet等无序集合的元素,每个元素将会按照某种随机的次序出现。虽然可以确定在迭代过程中能够遍历到集合中所有的集合元素,但却无法预知元素被访问的次序。
注意:java集合类库中的迭代器与其他类库中的迭代器在概念上有重要的区别。在传统的类库中,比如C++的标准模版库,迭代器是根据数组索引建模的。这样的话,就可以根据数组索引i来查看数组元素a[i]。但是java迭代器不是这样操作,它查找一个元素的唯一方法是调用next,而在执行查找操作的同时,迭代器的位置随之向前移动。
因此,应该将java迭代器默认为位于两个元素之间。当调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。
2.删除元素
Iterator接口的remove方法将会删除上次调用next方法时返回的元素。即使想要删除指定位置上的元素,仍然要越过这个元素。更重要的是,对next和remove方法的调用具有相互依赖性。如果调用remove之前没有调用next将是不合法的。如果这样做,会抛出一个IllegalStateException异常。
3.泛型实用方法
由于Collection和Iterator都是泛型接口,可以编写操作任何集合类型的实用方法。下面是一个用于检测集合是否包含指定元素的泛型方法:
1 public static <E> boolean contains(Collection<E> c,Object obj) 2 { 3 for(E element : c) 4 if(element.equals(obj)) 5 return true; 6 return false; 7 }
事实上,Collection接口声明了很多有用的方法,所有的实现类都必须提供这些方法。比如:
int size();
boolean isEmpty();
boolean contains(Object obj);
boolean containsAll(Collection<?> c);
boolean equals(Object obj)
boolean addAll(Collection<? extends E> from)
boolean remove(Object obj)
boolean removeAll(Collection<?> c)
void clear();
boolean retainAll(Collection<?> c)
Java类库提供了一个类AbstractCollection。一个具体的集合类可以扩展AbstractCollection。