Iterator源码分析
上一篇[集合类] 源码解析1(Iterable、RandomAccess、Serializable、Cloneable
文章目录
分析都写在代码注释中了,希望大家耐心读。
1. 整体
接上一篇文章,这一篇我们来详细分析一下Iterator接口,以及常见的实现。下面是常用类的类图,没有Set是因为Set是一种特殊的Map,这个后面再说。
下面是接口定义,定义了迭代器的基本操作。
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
// 暂时忽略
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
Iterator下面有两个抽象,一个是ListIterator,一个是HashIterator
2. ListIterator
我们查看ListIterator接口,它继承了Iterator接口,除了继承的方法,他还自己定义了一系列用于List的迭代器方法。
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
void remove();
/**************华丽的分割线**********************/
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void set(E e);
void add(E e);
}
下面我们具体看一下各个类的实现
3. Vector
Vector是线程安全的动态增长的数组,就是线程安全的ArrayList。本文只分析其内部类Itr和ListItr,源码如下。
1)Itr
// 获取Itr对象
public synchronized Iterator<E> iterator() {
return new Itr();
}
// 获取index元素
E elementData(int index) {
return (E) elementData[index];
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount; // 记录操作次数,用来支持 fast fail机制,在迭代时不能修改容器
public boolean hasNext() {
// cursor == elementCount表示遍历到尾部
return cursor != elementCount;
}
public E next() {
// 锁Vector对象,保证不同的线程使用不同的迭代器操作同一Vector,同步执行
synchronized (Vector.this) {
// fast fail 机制,检查容器是否被修改
checkForComodification();
int i = cursor;
if (i >= elementCount)
throw new NoSuchElementException();
cursor = i + 1;
// 获取下一个cursor,并设置lastRet
return elementData(lastRet = i);
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
// 同上
synchronized (Vector.this) {
// 同上
checkForComodification();
// 调用Vector方法,并重新设置modCount
Vector.this.remove(lastRet);
expectedModCount = modCount;
}
// 设置当前cursor 为lastRet,上次操作的索引。
cursor = lastRet;
lastRet = -1;
}
@Override
public void forEachRemaining(Consumer<? super E> action) {
// ...
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
2)ListItr
// 获取ListItr对象
public synchronized ListIterator<E> listIterator() {
return new ListItr(0);
}
// 传入初始cursor值
public synchronized ListIterator<E> listIterator(int index) {
if (index < 0 || index > elementCount)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
// 继承了Itr,所以拥有Itr的所有方法,这里只定义了ListIterator特有的方法。
final class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
// 可以对比hasNext方法
public boolean hasPrevious() {
return cursor != 0;
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
// 对比next方法
public E previous() {
// 同上
synchronized (Vector.this) {
// 同上
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
cursor = i;
// 同样设置lastRet
return elementData(lastRet = i);
}
}
// 设置上次遍历的值
public void set(E e) {
if (lastRet == -1)
throw new IllegalStateException();
synchronized (Vector.this) {
checkForComodification();
Vector.this.set(lastRet, e);
}
}
// 添加到cursor前一个位置
public void add(E e) {
int i = cursor;
synchronized (Vector.this) {
checkForComodification();
// 调用Vector方法,添加到cursor的位置,使用数组拷贝,将后面的元素向后移动
Vector.this.add(i, e);
expectedModCount = modCount;
}
cursor = i + 1;
lastRet = -1;
}
}
总结一下
- cursor为当前索引。
- lastRet为上次返回数据的索引,如果调用了add或remove方法,lastRet为-1。
- expectedModCount记录操作次数,为fast fail机制作准备,在迭代时不能并发修改容器。
- 同步方法要锁Vector类,保证不同的迭代器对象同步操作同一个Vector容器
4. ArrayList
ArrayList和Vector的迭代器实现基本相同,只是不支持并发访问,代码贴出来,大家看一下就好。
1)Itr
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
// ...
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
2) ListItr
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
public ListIterator<E> listIterator() {
return new ListItr(0);
}
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[lastRet = i];
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
5. LinkedList
1)ListItr
// 大家应该记得LinkedList继承了抽象类AbstractSequentialList 抽象顺序列表
// java.util.AbstractSequentialList
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
// Node
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
// 定位第index个节点
Node<E> node(int index) {
// index在前一半,从前往后遍历,反之从后往前遍历
// 使用位运算,size / 2
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned; // 上一个返回的节点
private Node<E> next; // 下一个准备返回的节点,可以理解为当前节点
private int nextIndex; // 同样,下一个准备返回的索引,可以理解为当前索引
private int expectedModCount = modCount; // 维护操作次数
ListItr(int index) {
next = (index == size) ? null : node(index);
nextIndex = index;
}
// ArrayList中使用的是 != 符号
// ArrayList中的cursor和LinkedList的nextIndex的操作只有++ 和 -- ,两个类的作者都是同一个人
// 实在不知道这两种写法有什么区别,或者说真的就是没有区别,望大神指点。
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
// fast fail机制,后面就不再提了
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
// 更新lastReture next nextIndex
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
// 参考hasNext方法
public boolean hasPrevious() {
return nextIndex > 0;
}
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
// next == null 说明初始化index为size ->查看构造函数
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex - 1;
}
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
// 将lastreturned节点从链表中脱离出来
unlink(lastReturned);
// 如果之前调用previous方法,next == lastReturned,移除的是当前节点,则让当前引用指向下一个节点
// 否则之前调用的是next方法,lastReturned.next == next,移除的是next的前一个节点,则将当前索引减1
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
// 清除引用,方便GC
lastReturned = null;
expectedModCount++;
}
// 设置lastReturned节点的值
public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}
public void add(E e) {
checkForComodification();
lastReturned = null;
// 说明初始化index为size, 添加到链表尾
if (next == null)
linkLast(e);
else
// 添加到当前节点的前面
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
public void forEachRemaining(Consumer<? super E> action) {
// ...
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
下面总结一下各个方法做了什么:
- next方法:将当前节点的值返回,更新当前节点、当前索引,记录lastReturned
- previous方法:如果初始化index为size,则将当前节点和lastReturned都指向最后一个节点。否则将当前节点和lastReturned都指向当前节点的前驱节点。将索引值减1.
- remove方法:删除lastReturned指向的节点。如果当前节点next也指向被删除的节点,则将next指向下一个节点,否则当前索引减1.
- set方法:比较简单,直接修改lastReturned指向的节点的值
- add方法:如果初始化index为size,则添加到链表尾部,否则添加到当前节点的前面。当前索引+1.
2)DescendingIterator
Descending Iterator 翻译成中文是 下降迭代器。顾名思义,他是反向遍历的迭代器,只是对ListItr进行了简单的封装,源码如下。
public Iterator<E> descendingIterator() {
return new DescendingIterator();
}
private class DescendingIterator implements Iterator<E> {
private final ListItr itr = new ListItr(size());
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
}
6. PriorityQueue
PriorityQueue相比其他容器,存在 删除节点时节点上浮到已经遍历的位置 的问题。重点是使用forgetMeNot队列保存上浮的节点,最后遍历,代码如下。
public Iterator<E> iterator() {
return new Itr();
}
private final class Itr implements Iterator<E> {
// 当前索引
private int cursor = 0;
// 上一个返回的索引
private int lastRet = -1;
// 在remove方法中,调用Vector的removeAt方法。
// removeAt方法中会将最后一个节点替换到被删除的元素的位置
// 然后进行下沉操作siftDown,如果没有执行,说明当前节点比子节点都大
// 这时进行上浮操作siftUp,如果节点上浮,说明当前节点比父节点小
// 即当前节点上浮到已经遍历过的位置,此时使用forgetMeNot队列保存节点,最后再遍历
private ArrayDeque<E> forgetMeNot = null;
// 上一个返回的节点
private E lastRetElt = null;
// 同上,fast fail机制
private int expectedModCount = modCount;
public boolean hasNext() {
// 首先判断索引是否超过size,没有直接返回,一定有next
return cursor < size ||
// 索引超过size后,查看forgetMeNot队列
// 有节点说明在之前remove时,有上浮到已经遍历过的位置的节点,返回true
(forgetMeNot != null && !forgetMeNot.isEmpty());
}
@SuppressWarnings("unchecked")
public E next() {
if (expectedModCount != modCount)
throw new ConcurrentModificationException();
if (cursor < size)
return (E) queue[lastRet = cursor++];
// 索引超过size后,查看forgetMeNot队列中是否有剩余的,在之前remove时上浮到已经遍历过的位置的节点
// 有则继续遍历forgetMeNot队列
if (forgetMeNot != null) {
lastRet = -1;
// 记录上一个返回节点
lastRetElt = forgetMeNot.poll();
if (lastRetElt != null)
return lastRetElt;
}
throw new NoSuchElementException();
}
public void remove() {
if (expectedModCount != modCount)
throw new ConcurrentModificationException();
if (lastRet != -1) {
// 后面PriorityQueue类专题会分析removeAt方法
// 方法会将最后一个节点替换到被删除的位置,再进行下沉、上浮
// 通过返回值来说明是否上浮,不为null说明上浮了,返回目标节点
E moved = PriorityQueue.this.removeAt(lastRet);
lastRet = -1;
// moved == null说明最后一个节点替换到被删除位置后没有上浮
if (moved == null)
cursor--;
// 否则,说明节点上浮到已经遍历的位置,就将节点加到队列中,等待最后遍历
else {
if (forgetMeNot == null)
forgetMeNot = new ArrayDeque<>();
forgetMeNot.add(moved);
}
} else if (lastRetElt != null) {
// 进入这里,说明上一次遍历是遍历forgetMeNot队列,则不存在上浮的问题
// 通过遍历找到目标节点索引,调用removeAt删除。(方法实现在本段代码最后)
PriorityQueue.this.removeEq(lastRetElt);
lastRetElt = null;
} else {
throw new IllegalStateException();
}
// 删除节点,修改操作次数
expectedModCount = modCount;
}
}
boolean removeEq(Object o) {
for (int i = 0; i < size; i++) {
if (o == queue[i]) {
removeAt(i);
return true;
}
}
return false;
}
7. HashMap
HashMap中Key、Value封装成Entry保存,所以遍历时有三种方式,Key、Value和Entry。HashMap使用HashIterator用来实现基本遍历操作,再用KeyIterator、ValueIterator和EntryIterator封装next方法。
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
// 省略方法...
}
abstract class HashIterator {
// 其实可以把next理解成当前节点,current理解成lastReturned节点,像之前那样
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot 桶索引
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
// 初始化next,找到第一个不为空的桶,next引用其第一个节点
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
// ******************核心***********************
// 更新current的值为next,next为更新后current的next
// 如果next为空,说明当前桶遍历完毕,进入下一个
if ((next = (current = e).next) == null && (t = table) != null) {
// 找到下一个不为空的桶,next引用其第一个节点
do {} while (index < t.length && (next = t[index++]) == null);
}
// ******************核心***********************
return e;
}
// 移除current节点
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
// 调用HashMap的removeNode方法
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
// 下面是获取迭代器的方法
// HashMap.KeySet
public final Iterator<K> iterator() {
return new KeyIterator();
}
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() {
return nextNode().key;
}
}
// HashMap.Values
public final Iterator<V> iterator() {
return new ValueIterator();
}
final class ValueIterator extends HashIterator
implements Iterator<V> {
public final V next() {
return nextNode().value;
}
}
// HashMap.entrySet
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() {
return nextNode();
}
}
8. TreeMap
abstract class PrivateEntryIterator<T> implements Iterator<T> {
Entry<K,V> next; // 当前节点
Entry<K,V> lastReturned; // 上一个返回的节点
int expectedModCount; // 操作次数 fast fail机制
PrivateEntryIterator(Entry<K,V> first) {
expectedModCount = modCount;
lastReturned = null;
next = first;
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
// 找到后继节点
next = successor(e);
lastReturned = e;
return e;
}
final Entry<K,V> prevEntry() {
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
// 找到前驱节点
next = predecessor(e);
lastReturned = e;
return e;
}
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
// 删除上一个返回的节点
// 如果他有一个孩子,则子树则会替代他的位置
// 如果他有两个孩子,则会使其后继节点(右子树的最左孩子)替代他的位置,就需要调整next引用到lastReturned
// deleted entries are replaced by their successors
if (lastReturned.left != null && lastReturned.right != null)
next = lastReturned;
deleteEntry(lastReturned);
expectedModCount = modCount;
lastReturned = null;
}
}
// 下面是获取迭代器的方法
// TreeMap.EntrySet
public Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator(getFirstEntry());
}
final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> {
EntryIterator(Entry<K,V> first) {
super(first);
}
public Map.Entry<K,V> next() {
return nextEntry();
}
}
// TreeMap.Values
public Iterator<V> iterator() {
return new ValueIterator(getFirstEntry());
}
final class ValueIterator extends PrivateEntryIterator<V> {
ValueIterator(Entry<K,V> first) {
super(first);
}
public V next() {
return nextEntry().value;
}
}
Iterator<K> keyIterator() {
return new KeyIterator(getFirstEntry());
}
final class KeyIterator extends PrivateEntryIterator<K> {
KeyIterator(Entry<K,V> first) {
super(first);
}
public K next() {
return nextEntry().key;
}
}
Iterator<K> descendingKeyIterator() {
return new DescendingKeyIterator(getLastEntry());
}
final class DescendingKeyIterator extends PrivateEntryIterator<K> {
DescendingKeyIterator(Entry<K,V> first) {
super(first);
}
public K next() {
return prevEntry().key;
}
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
deleteEntry(lastReturned);
lastReturned = null;
expectedModCount = modCount;
}
}