Java集合(三) ArrayList詳解

卡農Canon發表於2017-12-12

  前面的學習中我們知道,集合中存放了我們隨時可能需要使用到的物件,集合類提供增刪改等基本介面。就好比盛東西的容器,從某種意義上說,陣列也是一種容器。但是陣列太簡陋了,在使用之前必須指定長度,不能動態擴容,沒有方便的增刪改介面,沒有迭代器。唯一的優點就是簡單直接。因此Java為了彌補陣列的不足,提供了豐富的集合類。今天我們將對集合類中的ArrayList進行詳細的學習。

列表類

  在學習ArrayList之前,我們得先對List介面進行一個簡單的瞭解。List介面定義了列表類。在List的原始碼中,有非常詳細的註釋。這裡給大家看一下注釋的第一段:

/**
 * An ordered collection (also known as a <i>sequence</i>).  The user of this
 * interface has precise control over where in the list each element is
 * inserted.  The user can access elements by their integer index (position in
 * the list), and search for elements in the list.<p>
 *
 * Unlike sets, lists typically allow duplicate elements.
 */
複製程式碼

  這一段說明了List這個介面的作用,是一個有序的容器,使用這個介面的人,可以精確地控制資料存放在列表的什麼位置,使用者還可以通過一個整型的索引去檢索容器裡的某個元素,還有,List和Set最大的不同就是, List中允許元素是重複的。大家在學習過程中可以多讀一讀這些註釋。
  List繼承自Collection,和Collection比較,List 還新增了以下操作方法:

  • 增刪改查:add(index,object)、remove(index)、set(index,object)、get(index);
  • 搜尋:indexOf(),lastIndexOf();
  • 迭代器:listIterator();
  • 獲取列表中的小列表:subList(int fromIndex, int toIndex);

ArrayList

概述

  以陣列實現。節約空間,但陣列有容量限制。超出限制時會增加50%容量,用System.arraycopy()複製到新的陣列,因此最好能給出陣列大小的預估值。預設第一次插入元素時建立大小為10的陣列。
  按照陣列索引訪問元素:get(int index)/set(int index)的效能很高,這是陣列的優勢。直接在陣列末尾加入元素:add(e)的效能也高,但如果按索引插入、刪除元素:add(i,e)、remove(i)、remove(e),則要用System.arraycopy()來移動部分受影響的元素,效能就變差了,這是陣列的劣勢。
  ArrayList不是執行緒安全的,只能在單執行緒環境下,多執行緒環境下可以考慮用Collections.synchronizedList(List list)方法返回一個執行緒安全的ArrayList物件,也可以使用concurrent併發包下的CopyOnWriteArrayList類。
  ArrayList實現了Serializable介面,因此它支援序列化,能夠通過序列化傳輸,實現了RandomAccess介面,支援快速隨機訪問,實際上根據原始碼我們知道就是通過索引序號進行快速訪問,實現了Cloneable介面,能被克隆。

ArrayList原始碼解析

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    //序列號版本
    private static final long serialVersionUID = 8683452581122892189L;
    
    //預設初始容量為10
    private static final int DEFAULT_CAPACITY = 10;

    //共享空陣列例項用於空例項
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //共享空陣列例項用於預設大小的空例項
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //ArrayList基於該陣列實現,用該陣列儲存資料
    transient Object[] elementData; 

    //ArrayList中實際資料的數量
    private int size;

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

    //ArrayList無參構造方法。當元素第一次被加入時,擴容為預設大小10
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    //建立一個包含Collection的ArrayList
    public ArrayList(Collection<? extends E> c) {
        //呼叫toArray()方法把collection轉換為陣列
        elementData = c.toArray();
        //將轉換後的 Object[] 長度賦值給當前 ArrayList 的 size,並判斷是否為 0 
        if ((size = elementData.length) != 0) {
            if (elementData.getClass() != Object[].class)
                 // 若 c.toArray() 返回的陣列型別不是 Object[],則利用 Arrays.copyOf(); 來構造一個大小為 size 的 Object[] 陣列 
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //換成空陣列
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    //將當前容量值設為實際元素個數
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            //調整陣列緩衝區elementData,變為實際儲存大小Arrays.copyOf(elementData,size)
            elementData = (size == 0)? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size);
        }
    }

    //確定ArrayList的容量。(指定最小容量)
    public void ensureCapacity(int minCapacity) {
        //最小擴容,預設是10
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0: DEFAULT_CAPACITY;
        //如果使用者指定的最小容量>最小擴容10,就以使用者指定為準
        if (minCapacity > minExpand) {
            //確定明確的容量
            ensureExplicitCapacity(minCapacity);
        }
    }

    //私有方法:確定ArrayList的容量大小
    private void ensureCapacityInternal(int minCapacity) {
        //確保容量大小>=預設大小
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //確定明確容量
        ensureExplicitCapacity(minCapacity);
    }

    //確定ArrayList的具體大小
    private void ensureExplicitCapacity(int minCapacity) {
        //將“修改統計數”+1,該變數主要是用來實現fail-fast機制
        modCount++;
        // 超出了陣列可容納的長度,需要進行動態擴充套件
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    //要分配的陣列的最大大小
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //擴容。確保至少能容納最小容量引數指定的元素個數。
    //這是動態擴容的精髓,ArrayList的奧祕一覽無餘
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //得到陣列的舊容量,進行oldCapacity + (oldCapacity >> 1),將oldCapacity右移一位,相當於oldCapacity/2
        //這樣的結果便是將新陣列的容量擴充套件到原來陣列的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //判斷新陣列的容量夠不夠,夠了就直接使用這個大小建立新的陣列
        //不夠就將陣列大小設定為需要的大小
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //在判斷有沒有超過上面的最大容量限制,超出限制就調hugeCapacity()方法進行處理
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //將原來陣列的值copy新陣列中去,ArrayList的引用指向新陣列
        //這兒會新建立陣列,如果資料量很大,重複的建立陣列,會影響效率
        //因此最好在合適的時候通過構造方法指定預設的capaticy大小
        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;
    }

    //返回ArrayList的實際大小
    public int size() {
        return size;
    }
    
    //返回ArrayList是否為空
    public boolean isEmpty() {
        return size == 0;
    }

    //ArrayList是否包含Object(o)
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    //正向查詢,返回元素的索引值
    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 int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    //克隆函式
    //對拷貝出來的ArrayList物件的操作,不會影響原來的ArrayList
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            //將當前ArrayList的全部元素拷貝到v中
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }

    //返回ArrayList的Object陣列
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    //返回ArrayList元素組成的陣列
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        //如果陣列a的大小 < ArrayList的元素個數
        if (a.length < size)
            //就新建一個T[]陣列,陣列大小為ArrayList的元素個數,然後將ArrayList全部拷貝到新陣列中
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            
       //如果陣列a的大小 >= ArrayList的元素個數
       //就將ArrayList的全部元素都拷貝到陣列中
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

    //獲取index位置的元素值
    public E get(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        return (E) elementData[index];
    }

    //設定index位置的值為element
    public E set(int index, E element) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        E oldValue = (E) elementData[index];
        elementData[index] = element;
        return oldValue;
    }

     //新增元素
     //根據傳入的最小需要容量minCapacity來和陣列的容量長度對比,若minCapactity大於或等於陣列容量,則需要進行擴容。
    public boolean add(E e) {
        //確定ArrayList的容量大小
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //新增e到ArrayList中
        elementData[size++] = e;
        return true;
    }

    //將e新增到ArrayList的指定位置
    public void add(int index, E element) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

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

    //刪除ArrayList指定位置的元素
    public E remove(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        modCount++;
        E oldValue = (E) elementData[index];
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }

    //刪除ArrayList的指定元素
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            //遍歷ArrayList,找到元素o,則刪除,並返回true.
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

    //快速刪除第index個元素
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        //從 index+1 開始,用後面的元素替換前面的元素。
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
        //將最後一個元素設為null
        elementData[--size] = null; // clear to let GC do its work
    }

    //清空ArrayList,將全部的元素設為null
    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

    //將集合c追加到ArrayList中
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

    //從index位置開始,將集合c新增到ArrayList
    public boolean addAll(int index, Collection<? extends E> c) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

    //刪除fromIndex到toIndex之間的全部元素
    protected void removeRange(int fromIndex, int toIndex) {
        if (toIndex < fromIndex) {
            throw new IndexOutOfBoundsException("toIndex < fromIndex");
        }

        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

 
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

    //刪除ArrayList中包含Collection c中的的元素
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

    //保留ArrayList中包含Collection c中的的元素
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    //批量刪除
    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,elementData,w,size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

    //java.io.Serializable的寫入方法
    //將ArrayList的容量,所有的元素值都寫入到輸出流中
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // 寫入陣列的容量
        s.writeInt(size);

        // 寫入陣列的每一個元素
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    //java.io.Serializable的讀取方法:根據寫入方式讀出
    //先將ArrayList的容量讀出,再將所有的元素值讀出
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // 從輸入流中讀取ArrayList的容量
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);

            Object[] a = elementData;
            //從輸入流中將所有的元素值讀出
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

    //返回一個ListIterator
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

    //返回一個ListIterator迭代器,該迭代器是fail-fast機制的
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

    //返回一個Iterator迭代器,該迭代器是fail-fast機制的
    public Iterator<E> iterator() {
        return new Itr();
    }
    
    //AbstractList.Itr的優化版本,不做深究
    private class Itr implements Iterator<E> {
    ···
    }

    /**
     * AbAbstractList.ListItr 的優化版本
     * ListIterator與普通的Iterator的區別:
     * 它可以進行雙向移動,而普通的迭代器只能單向移動
     * 它可以新增元素(有add()方法),而後者不行
     */
    private class ListItr extends Itr implements ListIterator<E> {
    ...  
    }

   
   
    //獲取從fromIndex到toIndex之間的子集合(左閉右開區間)
    /**
     * 如果fromIndex == toIndex,則返回空集合
     * 對該子集合的操作,會影響原有集合
     * 當呼叫了subList()後,若對原集合進行刪除操作(刪除subList中的首個元素)時,會丟擲異常
     * 該自己支援所有的集合操作
     */
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);    //合法性檢查
        return new SubList(this, 0, fromIndex, toIndex);
    }

    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        //越界檢查
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        //非法引數檢查
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +  ") > toIndex(" + toIndex + ")");
    }
    
    //巢狀內部類,實現了RandomAccess,提供快速隨機訪問特性
    private class SubList extends AbstractList<E> implements RandomAccess {
    ...
    }

    //1.8方法,用於函數語言程式設計
    @Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    //獲取一個分割器,java8開始提供
    @Override
    public Spliterator<E> spliterator() {
        return new ArrayListSpliterator<>(this, 0, -1, 0);
    }

    //基於索引的、二分的、懶載入的分割器
    static final class ArrayListSpliterator<E> implements Spliterator<E> {
    ...
    }

    //移除集合中滿足給定條件的所有元素 1.8新增
    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        int removeCount = 0;
        final BitSet removeSet = new BitSet(size);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked")
            final E element = (E) elementData[i];
            if (filter.test(element)) {
                removeSet.set(i);
                removeCount++;
            }
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }

        final boolean anyToRemove = removeCount > 0;
        if (anyToRemove) {
            final int newSize = size - removeCount;
            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i);
                elementData[j] = elementData[i];
            }
            for (int k=newSize; k < size; k++) {
                elementData[k] = null;  // Let gc do its work
            }
            this.size = newSize;
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }

        return anyToRemove;
    }

    //1.8新增 替換方法
    @Override
    @SuppressWarnings("unchecked")
    public void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            elementData[i] = operator.apply((E) elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    //排序
    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
}

複製程式碼

總結

  在對ArrayList進行原始碼分析的時候,發現ArrayList有很多需要考慮的點。基本上,剛剛的程式碼裡都寫上了,這裡我們再做個總結:
  1.ArrayList是基於陣列實現的,它的記憶體儲元素的陣列為 elementData;elementData的宣告為:transient Object[] elementData;
  2.ArrayList中EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDA他的使用;這兩個常量,使用場景不同。前者是用在使用者通過ArrayList(int initialCapacity)該構造方法直接指定初始容量為0時,後者是使用者直接使用無參構造建立ArrayList時。
  3.ArrayList預設容量為10。呼叫無參構造新建一個ArrayList時,它的elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA, 當第一次使用 add() 新增元素時,ArrayList的容量會為 10。
  4.ArrayList的擴容計算為 newCapacity = oldCapacity + (oldCapacity >> 1);且擴容並非是無限制的,有記憶體限制,虛擬機器限制。   5.ArrayList的toArray()方法和subList()方法,在源資料和子資料之間的區別;

  • toArray():對該方法返回的陣列,進行操作(增刪改查)都不會影響源資料(ArrayList中elementData)。二者之間是不會相互影響的。
  • subList():對返回的子集合,進行操作(增刪改查)都會影響父集合。而且若是對父集合中進行刪除操作(僅僅在刪除子集合的首個元素)時,會丟擲異常java.util.ConcurrentModificationException。
      6.對ArrayList進行操作(如add()、clear())後,即使elementData實際上>其內元素個數,但是再直接列印該list時,顯示結果還是[x,x,x] (注:x代表其內實際(或有效)儲存的元素)
      對於elementData中儲存情況和直接列印list(即System.out.println(list))結果不一致的原因,是因為AbstractCollection 中對toString()進行了定義。程式碼如下:
 public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }
複製程式碼

  7.注意擴容方法ensureCapacityInternal()。ArrayList在每次增加元素(可能是1個,也可能是一組)時,都要呼叫該方法來確保足夠的容量。當容量不足以容納當前的元素個數時,就設定新的容量為舊的容量的1.5倍加1,如果設定後的新容量還不夠,則直接新容量設定為傳入的引數(也就是所需的容量),而後用Arrays.copyof()方法將元素拷貝到新的陣列。從中可以看出,當容量不夠時,每次增加元素,都要將原來的元素拷貝到一個新的陣列中,非常之耗時,也因此建議在事先能確定元素數量的情況下,才使用ArrayList,否則不建議使用。

參考:

ArrayList原始碼分析
ArrayList的動態擴容核心

相關文章