ArrayList源碼深度剖析(一)

ArrayList概述

  • ArrayList是List接口的可調整大小的數組實現,具有動態擴展的能力,能夠動態的擴容和縮容。

  • 數組結構的特點
    • 查詢快:由於數組在內存中是一塊連續的空間,因此可以根據地址+索引的方式快速獲取對應位置的元素。

    • 增刪慢:每次增刪元素,都需要改變數組的長度,拷貝以及移動元素的位置。

繼承體系

  • ArrayList實現了List接口,爲ArrayList提供了基礎的添加、刪除、遍歷等操作。

  • ArrayList實現了RandomAccess接口,爲ArrayList提供了隨機訪問的能力。

    • RandomAccess接口的主要作用是允許通過算法改變其行爲,以便在應用於隨機訪問列表和順序訪問列表時提供良好的性能

    • 隨機訪問和順序訪問,如果集合實現了RandomAccess接口,那麼隨機訪問的效率要比順序訪問的效率要高

        public static void main(String[] args) {
          List<Integer> list = new ArrayList<>();
          //隨機訪問
          for (int i = 0; i < list.size(); i++) {
              list.get(i);
          }
    
          //順序訪問
          Iterator<Integer> iterator = list.iterator();
          while (iterator.hasNext()) {
              iterator.next();
          }
      }
    

/**
 * Marker interface used by <tt>List</tt> implementations to indicate that
 * they support fast (generally constant time) random access.  The primary
 * purpose of this interface is to allow generic algorithms to alter their
 * behavior to provide good performance when applied to either random or
 * sequential access lists.
 * <tt> List </ tt>
 *
 * 實現使用的標記接口,用於指示*它們支持快速(通常爲恆定時間)隨機訪問。
 * 該接口的主要目的是允許通用算法更改其行爲,以便在應用於隨機訪問或順序訪問列表時提供良好的性能。
 *
 * <p>The best algorithms for manipulating random access lists (such as
 * <tt>ArrayList</tt>) can produce quadratic behavior when applied to
 * sequential access lists (such as <tt>LinkedList</tt>).  Generic list
 * algorithms are encouraged to check whether the given list is an
 * <tt>instanceof</tt> this interface before applying an algorithm that would
 * provide poor performance if it were applied to a sequential access list,
 * and to alter their behavior if necessary to guarantee acceptable
 * performance.
 *
 * 用於操縱隨機訪問列表(例如ArrayList)的最佳算法在應用於*順序訪問列表
 * (例如LinkedList)時會產生二次行爲。
 * 鼓勵使用通用列表算法檢查給定列表是否爲該接口的 instanceof 接口,
 * 然後再應用一種算法如果將其應用於順序訪問列表則性能會較差並對其進行更改爲確保可接受的性能而必要的行爲。
 *
 * <p>It is recognized that the distinction between random and sequential
 * access is often fuzzy.  For example, some <tt>List</tt> implementations
 * provide asymptotically linear access times if they get huge, but constant
 * access times in practice.  Such a <tt>List</tt> implementation
 * should generally implement this interface.  As a rule of thumb, a
 * <tt>List</tt> implementation should implement this interface if,
 * for typical instances of the class, this loop:
 * 
 * 認識到隨機訪問和順序訪問之間的區別通常是模糊的。例如,某些 List 實現
 * 如果它們變得很大,則提供漸近線性的訪問時間,但實際上卻提供恆定的訪問時間。
 * 這樣的List 實現通常應該實現此接口。根據經驗,
 * 如果,對於類的典型實例,此循環如下: List 實現應實現此接口:
 * <pre>
 *     for (int i=0, n=list.size(); i &lt; n; i++)
 *         list.get(i);
 * </pre>
 * runs faster than this loop:
 * <pre>
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * </pre>
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @since 1.4
 */
public interface RandomAccess {
}
  • ArrayList實現了Cloneable接口,使得ArrayList可以被克隆。

  • ArrayList實現了Serializable接口,使得ArrayList可以被序列化。

  • ArrayList實現了Iterable接口,使得ArrayList具有可迭代的功能。

源碼剖析

ArrayList#clone方法源碼剖析

java.util.ArrayList#clone

    /**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     *
     * 返回此ArrayList實例的淺拷貝(元素本身不會被複制)
     *
     * @return a clone of this <tt>ArrayList</tt> instance
     */
    public Object clone() {
        try {
            //調用Object類的clone方法進行克隆,返回一個新的ArrayList實例
            ArrayList<?> v = (ArrayList<?>) super.clone();
            //Arrays.copyOf(elementData, size)方法返回新的數組實例(數組中的元素爲elementData數組中的元素)
            //將動態數組中的元素拷貝到新的ArrayList實例v中,
            v.elementData = Arrays.copyOf(elementData, size);
            //實際修改次數
            v.modCount = 0;

            //返回新的ArrayList實例
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

java.util.Arrays#copyOf(T[], int)

    /**
     * Copies the specified array, truncating or padding with nulls (if necessary)
     * so the copy has the specified length.  For all indices that are
     * valid in both the original array and the copy, the two arrays will
     * contain identical values.  For any indices that are valid in the
     * copy but not the original, the copy will contain <tt>null</tt>.
     * Such indices will exist if and only if the specified length
     * is greater than that of the original array.
     * The resulting array is of exactly the same class as the original array.
     *
     * 複製指定的數組,以空值截斷或填充(如有必要的話),以便副本具有指定的長度。
     * 對於在原始數組和副本中均有效的所有索引,兩個數組將包含相同的值。
     * 對於在副本中有效但在原始副本中無效的任何索引,副本將包含 null 值。
     * 僅當指定的長度大於原始數組的長度時,此類索引纔會存在。
     * 所得數組與原始數組具有完全相同的類。
     *
     * @param <T> the class of the objects in the array
     * @param original the array to be copied
     * @param newLength the length of the copy to be returned
     * @return a copy of the original array, truncated or padded with nulls
     *     to obtain the specified length
     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
     * @throws NullPointerException if <tt>original</tt> is null
     * @since 1.6
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] copyOf(T[] original, int newLength) {
        //調用copyOf(original, newLength, original.getClass())
        //返回一個T類型的數組
        return (T[]) copyOf(original, newLength, original.getClass());
    }

java.util.Arrays#copyOf(U[], int, java.lang.Class<? extends T[]>)

    /**
     * Copies the specified array, truncating or padding with nulls (if necessary)
     * so the copy has the specified length.  For all indices that are
     * valid in both the original array and the copy, the two arrays will
     * contain identical values.  For any indices that are valid in the
     * copy but not the original, the copy will contain <tt>null</tt>.
     * Such indices will exist if and only if the specified length
     * is greater than that of the original array.
     * The resulting array is of the class <tt>newType</tt>.
     *
     * 複製指定的數組,以空值截斷或填充(如有必要的話),以便副本具有指定的長度。
     * 對於在原始數組和副本中均有效的所有索引,兩個數組將包含相同的值。
     * 對於在副本中有效但在原始副本中無效的任何索引,副本將包含 null 值。
     * 僅當指定的長度大於原始數組的長度時,此類索引纔會存在。
     *
     * 產生的數組屬於newType 類。
     *
     * @param <U> the class of the objects in the original array
     * @param <T> the class of the objects in the returned array
     * @param original the array to be copied
     * @param newLength the length of the copy to be returned
     * @param newType the class of the copy to be returned
     * @return a copy of the original array, truncated or padded with nulls
     *     to obtain the specified length
     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
     * @throws NullPointerException if <tt>original</tt> is null
     * @throws ArrayStoreException if an element copied from
     *     <tt>original</tt> is not of a runtime type that can be stored in
     *     an array of class <tt>newType</tt>
     * @since 1.6
     */
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        /*
          如果((Object)newType == (Object)Object[].class)-(是否爲一個數組)添加滿足的話,
          則重新new了一個newLength長度的T類型的數組
          否則創建執行類型和長度的新數組
         */
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);

        //將原original數組中數據拷貝到copy這個新的數組中
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        //返回新的拷貝原來數組中元素後的新的數組的實例
        return copy;
    }

淺拷貝和深拷貝的對比

  • 淺拷貝在對基本數據類型的數據可以做到完全拷貝,而引用數據類型則不能(拷貝的時候,只是拷貝的引用),修改了引用類型的數據後,原對象中的引用類型也會進行修改。

  • 對象中的引用類型的對象需要實現Cloneable接口,重寫Object類的clone方法,而對象中重寫clone方法不能簡單的調用Ojbect類的clone方法,而需要先將基本數據類型進行拷貝,再將對象中的引用類型的對象進行拷貝,然後再賦值給原對象即可。

ArrayList類中的成員屬性

    /**
     * Default initial capacity.
     *
     * 默認容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     *
     * 用於空實例的共享空數組實例。
     */
    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 = {};

    /**
     * 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的容量是此數組緩衝區的長度。
     * 添加第一個元素時,任何具有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 
     * 的空ArrayList都將擴展爲DEFAULT_CAPACITY。
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * ArrayList的大小(它包含的元素數)
     * @serial
     */
    private int size;

java.util.ArrayList#ArrayList()構造方法源碼剖析

  • 在調用默認的無參構造器時,創建的是一個空的數組[],但是會在添加第一個元素的時候擴容爲默認的大小10。

    /**
     * Constructs an empty list with an initial capacity of ten.
     *
     * 構造一個初始容量爲10的空列表。
     */
    public ArrayList() {
        // 如果沒有傳入初始容量,則使用空數組DEFAULTCAPACITY_EMPTY_ELEMENTDATA
        // 使用這個數組是在添加第一個元素的時候會擴容到默認大小10
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

java.util.ArrayList#ArrayList(int)構造方法源碼剖析

  • 傳入初始容量,如果大於0就初始化elementData爲對應大小,如果等於0就使用EMPTY_ELEMENTDATA空數組,如果小於0拋出異常。

    /**
     * Constructs an empty list with the specified initial capacity.
     * 構造一個具有指定初始容量的空列表。
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            // 如果傳入的初始容量大於0,則new一個容量爲initialCapacity的數組存儲元素
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            // 如果傳入的初始容量等於0,使用空數組EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            // 如果傳入的初始容量小於0,拋出異常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

java.util.ArrayList#ArrayList(java.util.Collection<? extends E>)構造方法源碼剖析

  • 傳入集合並初始化elementData,這裏會使用拷貝把傳入集合的元素拷貝到elementData數組中,如果元素個數爲0,則初始化爲EMPTY_ELEMENTDATA空數組。

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * 構造一個包含指定集合的元素的列表,其順序由集合的迭代器返回
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        //將傳入的集合轉成數組
        elementData = c.toArray();
        //如果數組的長度不爲0
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            //c.toArray可能(不正確)不返回Object []
            //檢查c.toArray()返回的是不是Object[]類型,如果不是,重新拷貝成Object[].class類型
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            //如果集合轉成的數組的長度爲0,則初始化爲空數組EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

java.util.ArrayList#toArray()方法源碼剖析

    /**
     * Returns an array containing all of the elements in this list
     * in proper sequence (from first to last element).
     *
     * 以正確的順序(從第一個到最後一個元素)返回包含此列表中所有元素的數組。
     *
     * <p>The returned array will be "safe" in that no references to it are
     * maintained by this list.  (In other words, this method must allocate
     * a new array).  The caller is thus free to modify the returned array.
     *
     * 他返回的數組將是“安全的”,因爲此列表不維護對它的任何引用。
     * (換句話說,此方法必須分配一個新數組)。因此,調用者可以自由修改返回的數組。
     *
     * <p>This method acts as bridge between array-based and collection-based
     * APIs.
     *
     * 此方法充當基於數組的API和基於集合的API之間的橋樑。
     *
     * @return an array containing all of the elements in this list in
     *         proper sequence
     */
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章