0xCAFEBABE

talk is cheap show me the code

0%

java迭代器源码解析

Iterator 是java集合框架提供的一个接口,通过它可以更方便地对集合进行遍历, 那么问题来了,迭代器到底是怎么实现的呢? 为什么使用不当就会出现一些问题呢?带着这些问题, 我们以ArrayList为例, 走进源码来看看它的迭代器到底是怎么实现的, 话不多说直接上源码

首先当我们每次调用iterator()方法都会创建一个迭代器实例

1
2
3
public Iterator<E> iterator() {
return new Itr();
}

这个ItrArrayList的实现了Iterator内部类, 里面由三个属性:

cursor下一个将要返回的元素索引

lastRet最后一个返回的元素索引, 初始为-1

重点来看一下expectedModCount这个属性, 它保存了集合的一个”状态” 即集合被修改的次数,每次对ArrayList进行修改操作, 这个值就会+1, 所以每次调用iterator()创建出来的迭代器相当于保存了一份集合的’’快照’’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

而每次调用迭代器的next()方法时都会调用checkForComodification()对迭代器保存的状态与当前集合中的状态(修改次数)进行比较, 如果不一致就会抛出ConcurrentModificationException使这个迭代器失效从而保证了与集合中的数据的一致性, 而在remove()方法中, 实际上调用了ArrayListremove()方法, 并对状态(修改次数)进行了同步, 所以在迭代器的使用过程中, 只能使用其本身的remove()方法对元素进行删除, 而直接对原集合的修改操作都会导致迭代器失效, 同时因为ArrayList是线程不安全的,所以在next()方法中还对原集合的长度进行了”双重检查”, 如果在此期间被其他线程修改就会抛出ConcurrentModificationException