在ArrayList, LinkedList, HashMap集合类中会发现modCount这个字段应用在很多方法中,modCount字段继承自AbstractList类,官方描述为:
/**
* The number of times this list has been <i>structurally modified</i>.
* Structural modifications are those that change the size of the
* list, or otherwise perturb it in such a fashion that iterations in
* progress may yield incorrect results.
*
* <p>This field is used by the iterator and list iterator implementation
* returned by the {@code iterator} and {@code listIterator} methods.
* If the value of this field changes unexpectedly, the iterator (or list
* iterator) will throw a {@code ConcurrentModificationException} in
* response to the {@code next}, {@code remove}, {@code previous},
* {@code set} or {@code add} operations. This provides
* <i>fail-fast</i> behavior, rather than non-deterministic behavior in
* the face of concurrent modification during iteration.
*
* <p><b>Use of this field by subclasses is optional.</b> If a subclass
* wishes to provide fail-fast iterators (and list iterators), then it
* merely has to increment this field in its {@code add(int, E)} and
* {@code remove(int)} methods (and any other methods that it overrides
* that result in structural modifications to the list). A single call to
* {@code add(int, E)} or {@code remove(int)} must add no more than
* one to this field, or the iterators (and list iterators) will throw
* bogus {@code ConcurrentModificationExceptions}. If an implementation
* does not wish to provide fail-fast iterators, this field may be
* ignored.
*/
大致意思为:
这个字段是来记录list的结构性变化,这些变化是指改变了list长度的操作或者是导致迭代过程中发生错误的行为(比如在迭代过程中去修改list)。
在iterator和list iterator迭代器中使用了这个字段。如果这个字段在next, remove, previous, set, add等操作过程中被意外改变,迭代器将会抛出ConcurrentModificationException异常。
子类中是否使用这个字段是可选。如果子类希望实现迭代器快速失败,那么就应该在对list进行结构性修改时先去修改modCount字段。在迭代过程中不能进行add或remove操作,否在迭代器将抛出ConcurrentModificationExceptions异常。如果子类不希望实现快速失败迭代器的话,modCount字段可以忽略。
一句话总结,modCount是为了保证迭代过程中的快速失败。那么看看list的迭代器是如何实现的。
源码如下:
public Iterator<E> iterator() {
return new Itr();
}
iterator()返回了一个迭代器类,Itr是AbstractList的内部类
private class Itr implements Iterator<E> {
/**
*迭代器指针
*/
int cursor = 0;
/**
* 用来记录list上一步迭代位置
*/
int lastRet = -1;
/**
* 记录list修改次数
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
在next()方法中,先调用checkForComodification()方法检查modCount值是否有修改,然后获取指针位置的元素,接着指针指向下一个元素
在remove()方法中,先检查list是否是空,然后移除lastRet指向的元素并将cursor指针倒退一位,lastRet 重置为-1
因为不建议在集合类在迭代过程中去修改list的值,会导致不可预估的错误