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+napp

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;
    }

總結:dom

  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++;
    }

總結:ide

  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中集合的新特性;   有建議或着問題的,請在文末留言,本人水平有限,有錯誤或理解誤差,還請各位多多指導和見諒,如若轉載,請代表出處;

相關文章
相關標籤/搜索