1. 程式人生 > >Java ArrayList的自動擴容機制

Java ArrayList的自動擴容機制

注意:

不同的JDK版本的擴容機制可能有差異
實驗環境:JDK1.8

擴容機制

當向ArrayList中新增元素的時候,ArrayList如果要滿足新元素的儲存超過ArrayList儲存新元素前的儲存能力,ArrayList會增強自身的儲存能力,已達到儲存新元素的要求

ArrayList:本質通過內部維護的陣列物件進行資料儲存

①:分析ArrayList的add(E)方法

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return
true; }

分析:add方法首先通過ensureCapacityInternal()方法確保當前ArrayList維護的陣列具有儲存新元素的能力,經過處理之後將元素儲存在陣列elementData的尾部
elementData:ArrayList真正用於儲存元素的陣列

②:分析ensureCapacityInternal方法

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

分析:ensureCapacityInternal判斷ArrayList預設的元素儲存資料是否為空,為空則設定最小要求的儲存能力為必要儲存的元素和預設儲存元素個數的兩個資料之間的最大值,然後呼叫ensureExplicitCapacity方法實現這種最低要求的儲存能力

注意:ArrayList的儲存空間並不是需要一個建立一個,而是分階段性的建立,一般會預留儲存空間。
例如,如果ArrayList需要儲存10個元素,恰好ArrayList只能儲存6個元素,剩餘4個元素無法儲存,ArrayList可能會一次性擴充套件10個元素,這種ArrayList就有20個元素的儲存能力,在儲存能力範圍內,下次再存放元素,就不需要再次擴容

③:分析ensureExplicitCapacity方法:

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

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

分析:如果最低要求的儲存能力>ArrayList已有的儲存能力,這就表示ArrayList的儲存能力不足,因此需要呼叫 grow();方法進行擴容
④:分析grow()方法

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

分析:當ArrayList擴容的時候,首先會設定新的儲存能力為原來的1.5倍

 int newCapacity = oldCapacity + (oldCapacity >> 1);

如果擴容之後還是不能滿足要求則MAX_ARRAY_SIZE比較,求取最大值,
如果MAX_ARRAY_SIZE大小的能力還是不能滿足則通過hugeCapacity()方法獲取ArrayList能允許的最大值:

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

從hugeCapacity方法看出,ArrayList最大的儲存能力:儲存元素的個數為整型的範圍。
確定ArrayList擴容之後最新的可儲存元素個數時,呼叫
elementData = Arrays.copyOf(elementData, newCapacity);
實現elementData陣列的擴容,整個流程就是ArrayList的自動擴容機制工作流程

擴充套件:
ArrayList的自動擴容機制底層藉助於System實現

  public static native void arraycopy
  (Object src,  int  srcPos,
   Object dest, int destPos,
   int length);

arraycopy標識為native意味JDK的本地庫,不可避免的會進行IO操作,如果頻繁的對ArrayList進行擴容,毫不疑問會降低ArrayList的使用效能,因此當我們確定新增元素的個數的時候,我們可以事先知道並指定ArrayList的可儲存元素的個數,這樣當我們向ArrayList中加入元素的時候,就可以避免ArrayList的自動擴容,從而提高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);                                               
        }
    }