作为一个使用Java语言的开发者,对于迭代器应该不陌生,在对集合进行遍历时,几乎都能遇到。迭代器作为访问者和容器类之间的第三者,它提供了一种对集合元素进行顺序访问的统一实现方式。
定义
提供一种方法顺序的访问一个容器中的各个元素,而又不需要暴露对象的内部表示。
场景
遍历一个容器对象时。
角色
迭代器接口
定义、访问和遍历元素的接口
具体迭代器
迭代器的具体实现,记录当前游标位置
容器接口
提供创建具体迭代器角色的接口
具体容器类
具体迭代器与具体容器类进行关联
源码演示
因为迭代器一般由平台在内部进行了实现,比如说List
、Set
等。因此,本章节,就以Java的原生数据结构来分析。
我们来看下HashSet
的迭代器实现。
首先是容器接口类Set
public interface Set<E> extends Collection<E> {
int size();
// 创建迭代器的接口
Iterator<E> iterator();
boolean add(E e);
boolean remove(Object o);
}
看下实现类HashSet
对于获取迭代器的实现
private transient HashMap<E,Object> map;
...省略部分代码
/**
* Returns an iterator over the elements in this set. The elements
* are returned in no particular order.
*
* @return an Iterator over the elements in this set
* @see ConcurrentModificationException
*/
public Iterator<E> iterator() {
return map.keySet().iterator();
}
可以看到最终是调用了HashMap
的keySet
的iterator
方法。
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
从上述代码可以看出keySe
是一个KeySet
类型,接下来看下KeySet
的``iterator```方法。
public final Iterator<K> iterator() {
return new KeyIterator();
}
实际上就是返回了一个KeyIterator
对象。
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() {
return nextNode().key;
}
}
这里可以看出最终的逻辑还是在HashIterator
类里面
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.NoSuchElementException;
abstract class HashIterator {
HashMap.Node<K,V> next; // next entry to return
HashMap.Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot
HashIterator() {
expectedModCount = modCount;
HashMap.Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
final HashMap.Node<K,V> nextNode() {
HashMap.Node<K,V>[] t;
HashMap.Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
public final void remove() {
HashMap.Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
重点看下nextNode
方法,在这里返回了下一个节点的对象,并将next
指针向后移到动一位,从而实现遍历操作。代码看起来比较复杂,但是整体逻辑清晰,而且使用起来极为方便。
总结
迭代器模式的优点很明显也很单一,就是对容器元素提供遍历操作。它支持以不同的方式去遍历,也支持多个遍历同时进行,同时也弱化了容器了和遍历算法之间的关系。缺点也是设计模式的共同缺点,会增加类文件数量。