集合类中的modCount字段

在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的值,会导致不可预估的错误

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 【传智播客.黑马程序员训练营成都中心】 转载请注明出处 作者:成都校区.堂堂老师 1. 什么时候会产生并发修改异常...
    OpenCoder阅读 1,502评论 0 3
  • Java源码研究之容器(1) 如何看源码 很多时候我们看源码, 看完了以后经常也没啥收获, 有些地方看得懂, 有些...
    骆驼骑士阅读 1,009评论 0 22
  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,518评论 0 3
  • Java 集合框架系列 Java 集合框架_开篇Java 集合框架_ListJava 集合框架_ArrayList...
    wo883721阅读 875评论 0 3
  • 乡间,是那么诱人,独特,让你沉醉其中,是那么吸引,令人向往,还有什么风景能比得过这瑰丽的景色? 清晨,鸟儿叽叽喳喳...
    醉青海阅读 282评论 0 0