首先预览下Java源码中的Iterator和Iterable:
Iterable接口:
1 public interface Iterable<T> {//这里只摘录接口中的抽象方法 2 /** 3 * Returns an iterator over elements of type {@code T}. 4 * 5 * @return an Iterator. 6 */ 7 Iterator<T> iterator(); 8 9 }
Iterator接口:
public interface Iterator<E> { /** * Returns {@code true} if the iteration has more elements. * (In other words, returns {@code true} if {@link #next} would * return an element rather than throwing an exception.) * * @return {@code true} if the iteration has more elements */ boolean hasNext(); /** * Returns the next element in the iteration. * * @return the next element in the iteration * @throws NoSuchElementException if the iteration has no more elements */ E next(); }
用Iterator模式实现遍历集合
Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。
例如,如果没有使用Iterator,遍历一个数组的方法是使用索引: for(int i=0; i<array.size(); i++) { ... get(i) ... }
而访问一个链表(LinkedList)又必须使用while循环: while((e=e.next())!=null) { ... e.data() ... }
以上两种方法客户端都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。
更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。
解决以上问题,Iterator模式总是用同一种逻辑来遍历集合: for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
奥秘在于客户端自身不维护遍历集合的"指针",所有的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂方法生成,因此,它知道如何遍历整个集合。
客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。
首先看看Java.util.Iterator接口的定义:
public interface Iterator { boolean hasNext(); Object next(); void remove(); }
依赖前两个方法就能完成遍历,典型的代码如下:
for(Iterator it = c.iterator(); it.hasNext(); ) { Object o = it.next(); // 对o的操作... }
每一种集合类返回的Iterator具体类型可能不同,Array可能返回ArrayIterator,Set可能返回 SetIterator,Tree可能返回TreeIterator,但是它们都实现了Iterator接口,因此,客户端不关心到底是哪种 Iterator,它只需要获得这个Iterator接口即可,这就是面向对象的威力。
所有集合类都实现了 Collection 接口,而 Collection 继承了 Iterable 接口。
1 public interface Collection<E> extends Iterable<E> { }
而在具体的实现类中(比如 ArrayList),则在内部维护了一个 Itr 内部类,该类继承了 Iterator 接口,它的hasNext() 和 next() 方法是和 ArrayList 实现相耦合的。当调用 ArrayList 对象的 iterator() 方法的时候,返回该类 Itr 的一个实例,从而实现遍历 ArrayList 的功能。
1 /** 2 * An optimized version of AbstractList.Itr 3 */ 4 private class Itr implements Iterator<E> { 5 int cursor; // index of next element to return 6 int lastRet = -1; // index of last element returned; -1 if no such 7 int expectedModCount = modCount; 8 9 public boolean hasNext() { 10 return cursor != size; 11 } 12 13 @SuppressWarnings("unchecked") 14 public E next() { 15 checkForComodification(); 16 int i = cursor; 17 if (i >= size) 18 throw new NoSuchElementException(); 19 Object[] elementData = ArrayList.this.elementData; 20 if (i >= elementData.length) 21 throw new ConcurrentModificationException(); 22 cursor = i + 1; 23 return (E) elementData[lastRet = i]; 24 } 25 26 public void remove() { 27 if (lastRet < 0) 28 throw new IllegalStateException(); 29 checkForComodification(); 30 31 try { 32 ArrayList.this.remove(lastRet); 33 cursor = lastRet; 34 lastRet = -1; 35 expectedModCount = modCount; 36 } catch (IndexOutOfBoundsException ex) { 37 throw new ConcurrentModificationException(); 38 } 39 }
在遍历元素或者删除元素时,必须要进行next()方法,要不然,迭代器不能正常运行:如