所有的Collection系列的集合都包含了一个Iterator iterator() 方法;
1.Iterator接口的实现类在那里?
(1).例如ArrayList 里面创建内部类Itr implements Iterator接口
ArrayList list = new ArrayList();
Iterator lists = list.iterator();
public Iterator<E> iterator() {
return new Itr(); //创建内部类对象
}
//例如ArrayList里的内部类Itr implements Iterator接口
private class Itr implements Iterator<E> {
省略....
}
(2).例如vector内部也有个内部类Itr, iterator()方法 实现类是new Itr implements Iterator接口
和上面的Itr内部类没关系
Vector vector = new Vector();
Iterator vectors = vector.iterator();
public synchronized Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
省略....
}
(3).例如linkedList实现有点点差异
Itr内部类 implements Iterator接口
ListItr内部类继承Itr implements ListIterator接口
public Iterator<E> iterator() {
return listIterator(); //调用listIterator()
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index); //new ListItr对象,这个ListItr继承Itr
}
//ListItr内部类继承Itr implements ListIterator接口
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;
}
//Itr内部类 implements Iterator接口
private class Itr implements Iterator<E> {
省略...
}
结论:每一种Collection系列的集合的实现类都有一个内部类还实现了Iterator接口.
这个Iterator接口对象的作用是遍历,设计成内部类的好处,可以方便直接访问集合内部元素
好比飞机汽车火车上的空姐 只为当前的飞机里元素服务,别的飞机有别的空姐,反应出每个集合的迭代器只为当前的集合服务.
2.为什么Iterator迭代器和foreach遍历出现多线程并发修改问题?
net和remove同时访问报异常并发修改异常ConcurrentModificationException
public E next() {
// checkForComodification()因为都有检查修饰方法
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();
}
}
点击checkForComodification()方法
final void checkForComodification() {
//modCount变量修改次数和期望修改的次数不一样就报异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
例如在ArrayList里add()和remove()方法里都有modCount变量
public boolean add(E e) {
ensureCapacityInternal(size + 1); //点击此方法
elementData[size++] = e;
return true;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //每次添加都要加1
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
此代码省略..
modCount++; //每次删除都要修改
Iterator里代码
//去new iterator迭代器都会创建一个Itr对象
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor;
int lastRet = -1;
//new Itr就会获取到当前集合modcount的次数
int expectedModCount = modCount;
省略代码...
在foreach或获取Iterator跌代器对象,就用expectedModCount变量
记录当前集合modCount变量的次数expectedModCount = modCount
如果在遍历过程中,发现modCount != expectedModCount不相等
说明用集合add或remove等方法,修改了当前集合元素,就报并发修改异常
如何解决?
用Iterator迭代器自己删除方法 ,会重新修改expectedModCount变量的值,与modCount的值一样
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
rrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount; //修改又重新修改变量的值
新迭代器为什么要这样设计?
是为了避免其他线程修改集合的元素,导致当前操作的数据不正确
发现遍历的时候modCount != expectedModCount不一致快速失败
旧版的迭代器就不会快速失败,导致数据不一致.