【面試官】ArrayList集合默認長度是多少?

 

面試題目

 

面試官:“ArrayList集合默認長度是多少?”。

完美的回答:默認長度爲10。但是ArrayList的默認長度是有jdk版本差異的,在jdk8版本之前默認長度是10。而在jdk8版本的時候對ArrayList數組的默認長度進行了優化,將原來的默認長度10,改爲了初始長度爲0。當我們在首次添加元素,需要分配數組空間時,jdk自動幫我們進行了擴容操作,將初始數組長度擴容成了10。這樣做有效地降低了無用內存的佔用!

另外,它利用了數組擴容的特性來完成集合的這些功能,這也就是ArrayList集合查詢快、增刪慢的原因了!(如果你對這些集合的特點了解,可以附加這些內容,感覺爲了保險還是不要說,以免自己給自己挖坑!)

 
知識摘要
面臨這個問題,我們一定不要直接回答默認長度爲10或者0。

因爲ArrayList集合源於JDK的1.2版本,他開始的時候默認長度在jdk源碼裏是初始了10個長度。
而經過歷年的迭代,人們發現了問題,並在JDK8版本的時候做了優化。初始長度爲0,而在首次添加元素,需要實際分配數組空間,執行數組擴容操作時,擴容長度爲10。

優點:真正向數組中插入數據,用的時候再創建,或再加載,有效的降低無用內存的佔用

源碼(追完源碼你即可瞭解jdk是如何幫你實現的)

用於默認大小的空實例的共享空數組實例。我們將其與空的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.
     */
    //一個空對象,如果使用默認構造函數創建,則默認對象內容默認是該值
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

這是當有元素插入到數組中要擴容的默認長度10

/**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

Object數組

/**
     * 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.
     */
    transient Object[] elementData; // non-private to simplify nested class access

空對象

	// 一個空對象
	private static final Object[] EMPTY_ELEMENTDATA = new Object[0];

當前數組長度,也可以理解爲有效元素個數

	// 當前數組長度
	private int size;

數組最大長度

	// 數組最大長度
	private static final int MAX_ARRAY_SIZE = 2147483639;

add方法
add的方法有兩個,一個是帶一個參數的,一個是帶兩個參數的,下面我們將一個參數的add方法
add(E e) 方法
add主要的執行邏輯如下:
1)確保數組已使用長度(size)加1之後足夠存下 下一個數據
2)修改次數modCount 標識自增1,如果當前數組已使用長度(size)加1後的大於當前的數組長度,則調用grow方法,增長數組,grow方法會將當前數組的長度變爲原來容量的1.5倍。
3)確保新增的數據有地方存儲之後,則將新元素添加到位於size的位置上。
4)返回添加成功布爾值。

插入元素入口

//注:size我在這裏理解爲有效元素個數
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  //判斷擴容
        elementData[size++] = e;//將插入的值放在數組中(有效元素個數+1)
        return true;//返回添加成功的布爾值true
    }

判斷擴容入口

private void ensureCapacityInternal(int minCapacity) {
		//查看ensureExplicitCapacity和calculateCapacity方法源碼
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

ensureExplicitCapacity

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//忽略此句,這是父接口的計數器

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//傳入的參數(size+1)-Object數組長度>0的時候需要擴容
            grow(minCapacity);//具體擴容方法,並查看擴容方法
    }

grow

/**
     * 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;//原長度賦給oldCapacity
        int newCapacity = oldCapacity + (oldCapacity >> 1);//將數組長度擴容爲原來的1.5倍
        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);//複製數組元素到新長度的數組中
    }

calculateCapacity

//確保添加的元素有地方存儲,當第一次添加元素的時候this.size+1 的值是1,所以第一次添加的時候會將當前elementData數組的長度變爲10
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//Object數組長度==默認長度0時
            return Math.max(DEFAULT_CAPACITY, minCapacity);//返回默認長度10和傳入(size-1)的最大追
        }
        return minCapacity;//如果Object數組長度不等於默認長度0時,直接返回(size-1)
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章