集合接口,JAVA集合类库将接口与实现分离。下面以队列(queue)是如何分离的。
队列接口指出可以在队列的尾部添加元素,在队列的头部删除元素,并且可以查找队列中元素的个数,队列的特点是“先进先出”。一个队列接口的最小形式类似下面这样:
interface Queue<E> { void add(E element); E remove(); int size(); }
上面的接口没有说明队列是怎么实现的,队列的实现一般有两种方式(1)使用循环数组,在Java SE 6中可以通过使用ArrayDeque实现 (2)使用链表,可以使用LinkedList实现。
当在程序中使用队列时,一旦构建了集合就不需要知道就行使用了哪种实现,因此,只有在构建集合对象时,使用具体的类才有意义。可以使用接口类型存放集合的引用。
Queue<Customer> expressLane = new CircularArrayQueue<Customer>(100); expressLane.add(new Customer("Harry"));
利用这种方式,一旦改变了想法,可以轻松的使用另外一种实现,只需要对调用构造器的地方作出修改,如改为LinkedListQueue实现
Queue<Customer> expressLane = new LinkedListQueue<Customer>(); expressLane.add(new Customer("Harry"));
为什么选择这种实现而不选择另外一种实现呢?循环数组要比链表更高效,然而,循环数组是一个有界集合,即容量有限,如果程序中要收集的对象数量没有上限,就最好用链表来实现。
另外在API文档中,还会发现一组名字以Abstract开头的类,例如AbstractQueue,这些类市委类库实现这而设计的,如果实现自己的队列类,扩展AbstractQueue要比扩展Queue接口更方便。
Java类库中的集合接口和迭代接口
在Java类库中,集合类的基本接口是Collection接口,这个接口有两个基本方法。即
public interface Collection<E> { boolean add(E element); Iterator<E> iterator(); …… }
add方法用于向集合中添加元素,如果添加元素确实改变了集合就返回true,如果集合没有发生变化就返回false,例如在一个set中不允许有重复的对象,如果向set中再add一个已经存在的对象,那么这个请求就没有实效。
iterator方法用于返回一个实现了Iterator接口的对象,可以使用这个迭代器对象依次访问结合中的元素。
迭代器Iterator
Iterator接口包含3个方法:
public interface Iterator<E> { E next(); boolean hasNext(); void remove(); }
通过反复调用next() 方法,可以逐个访问集合中的每个元素,但是如果到达了集合的末尾,next方法将抛出一个NoSuchElementException异常。因此需要在next之前调用hasnext进行判断。下面实现访问集合中的所有元素:
Collection<String> c = . . .; Iterator<String> iter = c.iterator(); while (iter.hasNext()) { String element = iter.next(); do something with element }
从Java SE5 开始,可以使用for each 循环
for (String element :c) { do something with element }
编译器简单的将“for each”循环翻译为带有迭代器的循环。“for each”循环可以与任何实现了Iterable接口的对象一起工作,这个接口只包含一个方法:
public interface Iterable<E> { Iterator<E> iterator(); }
Collection接口扩展了Iterable接口,因此,对于标准类库中的任何集合都可以使用“for each”循环。
元素访问的顺序取决于集合类型,对于Arraylist进行迭代,从索引0开始,对于HashSet中的元素,按照某种随机的次序出现。
删除元素
Iterable接口的remove方法将会删除上次调用next方法时返回的元素,所以如果想删除指定位置上的元素,需要越过这个元素,再调用删除指令,例如:
Iterator<String> it = c.iterator(); it.next(); // skip over the first element it.remove(); // now remove it
next方法和remove方法的调用具有相互依赖性,如果调用remove之前没有调用next将是不合法的,会抛出一个IllegalStateException异常,例如,如果想删除两个相邻元素,不能直接的这样调用:
it.remove(); it.remove(); //error! 之前必须 添加一个 it.next();
泛型实用方法
由于Colletion与Iterator都是泛型接口,可以编写操作任何集合类型的使用方法,如下:下面检测任意集合是否包含指定元素的泛型方法:
public static <E> boolean contains(Collection<E> c, Object obj) { for (E element : c) if (element.equals(obj)) return true; return false; }
Collection接口中声明的类似的有用的方法还包括如下一些,所有实现类都必须提供这些方法的实现。
int size() boolean isEmpty() boolean contains(Object obj) boolean containsAll(Collection<?> c) boolean equals(Object other) boolean addAll(Collection<? extends E> from) boolean remove(Object obj) boolean removeAll(Collection<?> c) void clear() boolean retainAll(Collection<?> c) Object[] toArray() <T> T[] toArray(T[] arrayToFill)
为了方便的实现接口中以上的各类方法,Java类库提供了一个类AbstractCollection