ArrayList源码阅读笔记(1.8)

ArrayList类的注解阅读


/**
 * Resizable-array implementation of the <tt>List</tt> interface.  Implements
 * all optional list operations, and permits all elements, including
 * <tt>null</tt>.  In addition to implementing the <tt>List</tt> interface,
 * this class provides methods to manipulate the size of the array that is
 * used internally to store the list.  (This class is roughly equivalent to
 * <tt>Vector</tt>, except that it is unsynchronized.)

 
    这是一个实现了List接口的可变长度的数组。实现了list接口中的所有方法,允许存放所有的元素,包括null。除了实现list接口,该类还提供了一些方法来操作数组的大小,此数组被用来存储list的数据。(这个类和vector大致相当,除了它是线程不安全的)

  • ArrayList底层实现是数组,可存放重复数据,包括null,线程不安全
 *
 * <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
 * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
 * time.  The <tt>add</tt> operation runs in <i>amortized constant time</i>,
 * that is, adding n elements requires O(n) time.  All of the other operations
 * run in linear time (roughly speaking).  The constant factor is low compared
 * to that for the <tt>LinkedList</tt> implementation.
 *
 
    size(),isEmpty(),get(),set()方法使用的一个恒定时间(一个方法具有恒定的执行时间的,也就是代码不会因为问题规模n的变化而发生变化,时间复杂度记为O(1))。add操作花费恒定分摊时间,即插入n个元素需要o(n)的时间。 粗略的来说所有其他操作都以线性时间运行。(即这些操作与元素的个数成线性关系,操作的时间复杂度o(n))。这些操作与LinkedList实现相比,常数因子较低。
 
  • 底层为数组结构,相对于LinkedList效率较高
 * <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is
 * the size of the array used to store the elements in the list.  It is always
 * at least as large as the list size.  As elements are added to an ArrayList,
 * its capacity grows automatically.  The details of the growth policy are not
 * specified beyond the fact that adding an element has constant amortized
 * time cost.
 *
    每个ArrayList的实例对象都有一个容量(capacity)。这个容量就是这个list中用来存储元素的数组的大小。它至少和list的大小一样大。当有元素被增加到集合中时,它的容量会自动增加。除了要求添加一个元素的效率为“恒定分摊时间”,对于具体实现的细节没有特别的要求。
    

 * <p>An application can increase the capacity of an <tt>ArrayList</tt> instance
 * before adding a large number of elements using the <tt>ensureCapacity</tt>
 * operation.  This may reduce the amount of incremental reallocation.
 
    在大批量插入元素前,使用ensureCapacity()方法来增加集合的容量。这或许能够减少扩容增加量的大小。
 * <p><strong>Note that this implementation is not synchronized.</strong>
 * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
 * and at least one of the threads modifies the list structurally, it
 * <i>must</i> be synchronized externally.  (A structural modification is
 * any operation that adds or deletes one or more elements, or explicitly
 * resizes the backing array; merely setting the value of an element is not
 * a structural modification.)  This is typically accomplished by
 * synchronizing on some object that naturally encapsulates the list.
 *
 
    注意这个实现类是非同步的。如果有多个线程同时操作一个ArrayList的实例。然后,至少有一个线程修改了list的结构,就必须在外部保证它的线程同步。(结构修改指的是增加或者删除一个或多个映射;如果仅仅是更改已经存在的
key和value值,不算做结构修改)。这通常需要在一个被封装好的list对象上,使用同步进行操作。
 
  • ArrayList是非同步的,线程不安全的
 * If no such object exists, the list should be "wrapped" using the
 * {@link Collections#synchronizedList Collections.synchronizedList}
 * method.  This is best done at creation time, to prevent accidental
 * unsynchronized access to the list:<pre>
 *   List list = Collections.synchronizedList(new ArrayList(...));</pre>
 *
 
    如果没有这样的对象存在,那么就需要使用Collections.synchronizedList方法来包装这个list对象,而且最好是在创建对象的时候就进行包装,这是为了预防对这个list对象进行一些线程不同步的操作。举个例子:List list = Collections.synchronizedList(new ArrayList(...));
 
  • 尽管有一个线程安全的类Vector和ArrayList结构类似,但是我们在需要保证线程安全时依然不会使用Vector这个类(过时的类),而是使用 Collections.synchronizedList()方法来包装得到一个线程安全的list对象。
 * <p><a name="fail-fast">
 * The iterators returned by this class's {@link #iterator() iterator} and
 * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>
 * if the list is structurally modified at any time after the iterator is
 * created, in any way except through the iterator's own
 * {@link ListIterator#remove() remove} or
 * {@link ListIterator#add(Object) add} methods, the iterator will throw a
 * {@link ConcurrentModificationException}.  Thus, in the face of
 * concurrent modification, the iterator fails quickly and cleanly, rather
 * than risking arbitrary, non-deterministic behavior at an undetermined
 * time in the future.
 *
 
    该类的集合视图方法返回的迭代器是fail-fast机制的:在迭代器被创建后,如果list对象被结构化修改后,无论在何时,使用何种方法(除了迭代器本身的remove方法和add方法)来修改它,都会抛出ConcurrentModificationException.因此,面对并发修改操作时,迭代器会迅速且清晰地报错.而不是冒着在不确定的时间做不确定的操作的风险.

  • fail-fast,它是Java集合中的一种错误检测机制。某个线程在对collection进行迭代时,不允许其他线程对该collection进行结构上的修改。否则程序就会抛出ConcurrentModificationException 异常。快速终止操作
 
 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
 * as it is, generally speaking, impossible to make any hard guarantees in the
 * presence of unsynchronized concurrent modification.  Fail-fast iterators
 * throw {@code ConcurrentModificationException} on a best-effort basis.
 * Therefore, it would be wrong to write a program that depended on this
 * exception for its correctness:  <i>the fail-fast behavior of iterators
 * should be used only to detect bugs.</i>

    注意,迭代器的fail-fast行为是不能保证的.一般来说,保证非同步的同步操作是不太可能的.在最优基础上,Fail-fast迭代器会抛出ConcurrentModificationException.因此,写一个为了自身正确性而依赖于这个异常的程序是不对的.迭代器的fail-fast行为应该只是用来检测bug而已.

  • 我们要主动封装list以便进行同步操作,程序要要避免此异常而不是使用此异常

ArrayList类的定义

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 继承的类
    AbstractList:抽象类,只需知道此类是List接口的简单通用实现

  • 实现的接口
    List:不多说了

    RandomAccess:(标记接口)代表支持随机访问
    Cloneable:(标记接口)代表 Object.clone() 方法可以合法地对该类实例进行按字段复制。(没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常)
    java.io.Serializable(标记接口)

属性的定义

    protected transient int modCount = 0;
    
  • 这是父类AbstractList的一个属性 :用于记录列表结构被修改的次数。每次列表结构被修改都会modCount++
    为什么要记录此数据呢?
    在线程不安全的集合中,正如上面所说:迭代器采用了fail-fast机制。而fail-fast机制触发原理就是比对expectedModCount 和 modCount 是否相等,不相等就报ConcurrentModificationException异常
    此处不理解没关系,后面会讲迭代器方法的源码时,就会明白了
/**
     * Default initial capacity.
     * 初始默认容量 为 10
     */
    private static final int DEFAULT_CAPACITY = 10;
    
/**
     * Shared empty array instance used for empty instances.
     * 
     * 指定该ArrayList容量为0时,返回该空数组。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

/**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     * 
     * 用于默认大小的空实例的共享空数组实例。
     * 这个空数组的实例用来给无参构造使用。当调用无参构造方法,返回的是该数组。
     * 将此与EMPTY_ELEMENTDATA区分开来,以便了解在添加第一个元素时要增加多少容量。
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

  • EMPTY_ELEMENTDATA 和 DEFAULTCAPACITY_EMPTY_ELEMENTDATA都是表示空数组实例
    区别在于:
    EMPTY_ELEMENTDATA 是用户指定初试容量为0时 使用它
    DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是默认创建初始容量为10的空数组,被无参构造器使用
    将此与EMPTY_ELEMENTDATA区分开来,以便了解在添加第一个元素时要增加多少容量
/**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     * 
     * 存储ArrayList元素的数组缓冲区
     * ArrayList的容量(capacity)就是是此数组缓冲区的长度。
     * 声明为transient 不会被序列化
     * 非私有 是为了方便内部类调用
     */
    transient Object[] elementData;    // non-private to simplify nested class access

  • 该值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,当第一次添加元素进入ArrayList中时, 数组将扩容至DEFAULT_CAPACITY。这也印证了为什么区分EMPTY_ELEMENTDATA,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
/**
     * The size of the ArrayList (the number of elements it contains).
     *
     * List中元素的个数
     */
    private int size;

  • 仅仅表示 该list包含的元素的个数,和数组容量没有任何关系

这里提一点:前面提到size()方法时间复杂度为O(1),是因为它将size存储起来了,牺牲了空间提高了效率。

ArrayList构造器

ArrayList有三个构造器

创建一个指定存储容量的空序列

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
  • 指定的initialCapacity
    >0时,创建的序列容量为initialCapacity
    ==0时,创建的是 EMPTY_ELEMENTDATA
    <0时,会报异常
无参构造,创建一个初始容量为10 的空序列

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

  • 此处使用的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA

遵循集合的约定 提供 一个可将Collection转换为ArrayList的构造器
这些元素是按照该 Collection 的迭代器返回它们的顺序排列的。

public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

  • 注意:toArray的方法返回的类型不一定是Object[] 这是jDK的bug,两个类之间有继承关系时,JDK允许向上转型(子类赋值给父类)而 向下转型(父类赋值给子类)是不允许的。为了解决这个问题需要检验运行时类型使用Arrays.copyOf将其转为Object[]类型

核心方法


/**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     * 
     * 将ArrayList的容量设置为当前size的大小,应用可以使用此方法最小化实例的存储空间
     *
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }
    
  • 注意:首先需要明确一个概念,ArrayList的size就是ArrayList的元素个数,length是ArrayList申请的内容空间长度。ArrayList每次都会预申请多一点空间,以便添加元素的时候不需要每次都进行扩容操作。此操作修改了列表结构,所以modCount++;

    /**
     * Increases the capacity of this <tt>ArrayList</tt> instance, if
     * necessary, to ensure that it can hold at least the number of elements
     * specified by the minimum capacity argument.
     * 
     * 如有必要,增加此ArrayList实例的容量,以确保它至少可以容纳由minCapacity参数指定的元
     * 素数。
     * 
     * @param   minCapacity   the desired minimum capacity
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
 
  • ensureCapacity方法中,minExpand 表示最小扩容量, minCapacity表示最小容量,在这里分了两种情况
    此实例 是默认大小的ArrayList,最小扩容量为DEFAULT_CAPACITY 否则为 0;然后比较minCapacity 和 minExpand,如果期望的最小容量比最小扩容量小就不扩容,反之使用minCapacity进行扩容

ensureCapacityInternal方法,数组容量检查,不够时则进行扩容,只供类内部使用,例如add(),addAll()等方法时会调用此方法进行容量检验,此时minCapacity 通常为size+n

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code 
        // 只有最小容量比当前容量大时才会进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    
    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     * 
     * 最大存储容量
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 先预先扩容1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            // 主要判断 预期最小容量 minCapacity 是否大于 MAX_ARRAY_SIZE
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

总结:

  1. 只有最小容量比当前容量大时才会进行扩容;
  2. 扩容操作时,会预先把容量扩容至自身容量的1.5倍(预扩容)(使用的是oldCapacity + (oldCapacity >> 1)),然后于需要的最小容量minCapacity进行比较,选其最大值;
  3. 最终需要的容量会判断是否超过数组最大容量MAX_ARRAY_SIZE,1.没有超过 ——> 生成新的容量数组;2.超过了 ——> 会进行判断(1.是需要的最小容量超过了MAX_ARRAY_SIZE ——> 最终容量设为Integer.MAX_VALUE; 2.还是预扩容超过了MAX_ARRAY_SIZE ——> 最终容量设为MAX_ARRAY_SIZE) ——> 生成新的容量数组;
  4. 使用最大容量MAX_ARRAY_SIZE时,要注意因为某些VM会在数组中保留一些头字,可能会导致array容量大于VM的limit,最终导致OutOfMemoryError。
  5. minCapacity<0时也会触发MAX_ARRAY_SIZE,但这种情况在我的认知下不会发生,可能是严谨的做法,安全检查;

普通方法


    public boolean contains(Object o) {
    	  // 借用indexOf的方法看是否存在
        return indexOf(o) >= 0;
    }
    
    // 实质就是遍历数组,使用Object的equals方法,返回-1为不存在此元素,lastIndexOf()方法就是反向遍历
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    
    
    public boolean add(E e) {
    	 // 检验是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 先在index=size的位置赋值e,再将ArrayList的size增加一位
        elementData[size++] = e;
        return true;
    }
    
    
    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
    

总结:

  1. add()一个参数直接加在数组最后
  2. add(index, element) 使用System.arraycopy()将index的位置空出来,将值赋值过去。System.arraycopy为 JVM 内部固有方法,它通过手工编写汇编或其他优化方法来进行 Java 数组拷贝,这种方式比起直接在 Java 上进行 for 循环或 clone 是更加高效的。数组越大体现地越明显。
    
    
    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        
        // 将数组最后一位 置 null,等待垃圾回收机制来回收
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
    
    
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }
    
    private class SubList extends AbstractList<E> implements RandomAccess {


迭代器(iterator&ListIterator)实现

ArrayList中的迭代器实现对AbstractList中的迭代器进行了优化

/**
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     * 
     * 按原有list的顺序返回一个迭代器,遵循fail-fast机制。
     * 
     * 
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }
    

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        // 后游标:指向下一个元素,等于下一个元素的索引值
        int cursor;       // index of next element to return
        // 前游标:指向当前元素,等于当前元素索引值,-1代表在最开始,还未指向元素
        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的remove
                ArrayList.this.remove(lastRet);
                // remove之后 后游标左移
                cursor = lastRet;
                // 重制前游标
                lastRet = -1;
                // 并且会使预期修改次数 和 实际修改次数 保持相等
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }


		  // 检查 实际修改次数 和 预期修改次数是否相等
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

  • 总结:
    使用迭代器便利的时候,remove元素时,要使用Iterator.remove(),虽然其本质也是调用ArrayList的remove()的方法,只是为了使 modCount,expectedModCount 保持相等,否则会报ConcurrentModificationException()异常
/**
     * Returns a list iterator over the elements in this list (in proper
     * sequence), starting at the specified position in the list.
     * The specified index indicates the first element that would be
     * returned by an initial call to {@link ListIterator#next next}.
     * An initial call to {@link ListIterator#previous previous} would
     * return the element with the specified index minus one.
     *
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence).
     *
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @see #listIterator(int)
     */
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

    
    /**
     * An optimized version of AbstractList.ListItr
     */
    private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }
        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 set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                // 在当前元素的后面加入此元素
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                // add 操作会导致 modCount++,所以这边要保持相等
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

  • remove和add操作成功后 lastRet都会重新赋值为-1,并且会执行expectedModCount = modCount操作,以防ConcurrentModificationException;

  • ListItr继承于Itr,增加了previous()等一些方法,最大不同是游标cursor可以向前移动了。

  • 注意:执行过next()方法后再执行previous(),当前元素并没有改变(lastRet没有变),只是cursor进行了了改变,不要进行常规思考 previous()操作就是当前元素向前移动,next()就是当前元素向后移动,准确来说是cursor进行前后移动,进行previous()操作时 lastRet始终等于cursor,next()操作时cursor始终比lastRet大1

最后声明

  源码版本为JDK1.8,只是对日常使用的基本操作的源码进行了分析,对于1.8的新特性并没有涉及,等将主要集合类源码分析完后,会专门出一篇分析一下1.8中集合的新特性;
  有建议或着问题的,请在文末留言,本人水平有限,有错误或理解偏差,还请各位多多指导和见谅,如若转载,请表明出处;

posted @ 2019-01-03 17:29  王诗文  阅读(242)  评论(0编辑  收藏  举报