ArrayList的擴容


ArrayList的介紹

  • ArrayList是List接口下的一個實現類,它可以動態的修改數組。
  • 可以加入null,並且可以加入多個。
  • 是由數組來實現存儲數據的。
  • ArrayList基本等同於Vector,但是ArrayList是線程不安全的。
  • ArrayList中維護了一個Object類型的數組elementData。

使用無參構造器創建ArrayList數組時的擴容(一)

public class ArrayListSource {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        for (int i = 1; i < 11; i++) {
            arrayList.add(i);
        }
        arrayList.add(100);
        arrayList.add(200);
        arrayList.add(300);
        arrayList.add(400);
    }
}
ArrayList arrayList = new ArrayList();
使用無參構造函數創建對象,先會創建一個空的elementData數組
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;

(第一次進入add添加數字)for循環添加數字的時候,會首先進行一個裝箱操作。

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

然后進入ArrayList類的add方法。

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

add方法中首先判斷是否需要擴容,進入ensureCapacityInternal方法。

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //第一次進入該方法時,兩個數組相同,if判斷為true
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            //private static final int DEFAULT_CAPACITY = 10;
            //將兩者中的大的那個賦給minCapacity,傳入的minCapacity為1,經過賦值操作后,變為了10
        }

        ensureExplicitCapacity(minCapacity);
    }

進入ensureExplicitCapacity方法確認是否需要擴容。

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

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        //此時minCapacity大小為10,數組長度為0,所以if判斷為true,進入grow真正的擴容方法
            grow(minCapacity);
    }

進入grow擴容。

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //>>右移運算相當於除以2
        //oldCapacity=newCapacity=0
        if (newCapacity - minCapacity < 0)
        //if判斷為true,newCapacity的值變為10
            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);
        //進行數組的拷貝
    }

依次返回后,將數據存入數組下標為0的地方。然后執行size++。

執行完上述操作后,集合的大小就變為了10,並且可以看到在0的位置存入了數據。

實際上第一次沒有真正用到1.5倍的擴容。

使用無參構造器創建ArrayList數組時的擴容(二)

第二次進入for循環的add方法時,在ensureCapacityInternal方法中,if判斷為false,直接進入ensureExplicitCapacity方法。

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

        ensureExplicitCapacity(minCapacity);
        //此時傳入的參數為數組中數據個數多少再加1,minCapacity=2
    }

ensureExplicitCapacity方法中,不進入grow。

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

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        //minCapacity為2,elementData.length為10,不進入grow方法
            grow(minCapacity);
    }

返回后,將數據存入下標為1的地方。執行size++。

重復上述操作,直到for循環結束,存入十個數據。

使用無參構造器創建ArrayList數組時的擴容(三)

執行arrayList.add(100);也先進行裝箱操作。

再進入add,直到進入方法ensureExplicitCapacity.

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

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        //此時數組元素已滿,minCapacity的值為11,大於數組的長度,所以要進入grow方法,進行擴容
            grow(minCapacity);
    }
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);
    }

在grow方法中,將數組長度10賦值給oldCapacity。

新的數組容量newCapacity為原來數組容量的長度10加上,原數組長度除以2的值5,所以最后newCapacity的大小為15。

兩個if判斷都為false,最后執行Arrays.copyOf。

擴容后的數組大小為15。

使用有參構造器創建ArrayList數組時的擴容(一)

public class ArrayListSource {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList(8);
        for (int i = 1; i < 9; i++) {
            arrayList.add(i);
        }
        arrayList.add(100);
        arrayList.add(200);
        arrayList.add(300);
        arrayList.add(400);
    }
}

創建對象時,直接創建一個指定大小的數組。

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

然后進入for循環,先裝箱,再進入add方法——ensureCapacityInternal方法。

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

        ensureExplicitCapacity(minCapacity);
    }

if判斷為false,直接進入ensureExplicitCapacity。

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

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

minCapacity的值為1,數組長度為8。if判斷為false,返回,加入數據,size++。

使用有參構造器創建ArrayList數組時的擴容(二)

執行arrayList.add(100);

經過add——ensureCapacityInternal,直接進入ensureExplicitCapacity。

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

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

minCapacity的值為9,elementData.length的值為8,進入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);
    }

oldCapacity=8

newCapacity=8+4=12

不進入if,執行拷貝,擴容成功。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM