- 
例如使用 
 
 Arraylist
 
 集合返回的一个iterator迭代器,我们
 
 这样使用会报错
 
 :- 
ArrayList<Integer> arrayList = new ArrayList<>(); arrayList.add(1); Iterator<Integer> iterator = arrayList.iterator();//获得迭代器 arrayList.add(2); if (iterator.hasNext()) System.out.println(iterator.next());
 
- 
- 
 分析
 
 :- 
我们来看** 
 
 iterator.next()
 
 方法源码**: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]; } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
- 
 
 ArrayList
 
 
 继承了
 
 
 AbstractList
 
 ,
 
 其中**
 
 AbstractList
 
 ** 中有个**
 
 modCount
 
 ** 代表了
 
 集合修改的次数
 
 。在**
 
 ArrayList
 
 的
 
 iterator
 
 的
 
 next()
 
 方法中会判断**
 
 
 expectedModCount
 
 与
 
 
 
 modCount
 
 是否相等,如果相等继续执行,不相等报错
 
 。
- 
这个 
 
 expectedModCount
 
 是迭代器这个类的一个属性,
 
 调用
 
 ArrayList
 
 自身的
 
 add
 
 和“remove
 
 等改变集合大小的方法都会导致
 
 modCount+1
 
 ,但是不会修改
 
 expectedModCount`
 
 。
- 
返回的 
 
 迭代器是
 
 ArrayList
 
 的一个私有内部类(下文有这个内部类的源码)
 
 ,在调用集合的iterator()方法返回迭代器的时候底层是new一个新的迭代器返回,它在
 
 创建的时候会将当前
 
 modCount
 
 的值赋给
 
 expectedModCount
 
 ,因此创建的时候两者相等
 
 。
- 
 因此我们在创建迭代器后,如果使用了
 
 ArrayList
 
 本身的add方法导致
 
 modCount+1
 
 后,此时
 
 modCount
 
 和
 
 expectedModCount
 
 不相等了,再调用迭代器的next()方法就会报错
 
 。- 
注意:这里不止调用 
 
 add
 
 会报错,调用
 
 ArrayList
 
 本身的
 
 remove
 
 也会报错,
 
 关键在于这些方法修改了
 
 modCount
 
 但是没有修改
 
 expectedModCount
 
 
 。
- 
 如果我们是用迭代器的
 
 remove
 
 方法则不会报错,因为迭代器的remove方法在删除元素后会将新的
 
 modCount
 
 的值赋给
 
 expectedModCount
 
 
 :public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet;//这个cursor表示的是下一个需要遍历的元素,lastRet表示上一次遍历到的元素 lastRet = -1; expectedModCount = modCount;//这里会保持两者是一致的 } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }- 
           
 注意:我们在删除
 
 lastRet
 
 索引位置表示的上一个遍历的元素后,将
 
 lastRet
 
 的索引赋给
 
 cursor
 
 表示下一个需要遍历的索引位置
 
 。- 
             
 这个时候可能会有疑惑:为什么这个位置元素被删除了下一次遍历还是这个位置
 
 ?- 
               
 这是因为我们
 
 remove
 
 删除上一个元素后,数组大小-1,即被删除元素后的元素都会往前移动,此时lastRet这个索引在新数组中指向的就是刚刚的下一个元素
 
 。
 
- 
               
 
- 
             
- 
           
 删除之后将
 
 lastRet
 
 置为-1,而remove方法开始就会判断
 
 lastRet
 
 是否小于0,防止连续两次调用
 
 remove
 
 方法删除元素
 
 。
 
- 
           
 
- 
- 
ArrayList中的iterator私有内部类是这样定义的: 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; 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) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
 
- 
 
