天天看點

Java ArrayList new出來,預設的容量到底是0還是10 ?

前文  

最近也快到了金三銀四, 想該篇文章這種問題,貌似又有了熱度 :

Java ArrayList new出來,預設的容量到底是0還是10 ?
Java ArrayList new出來,預設的容量到底是0還是10 ?
Java ArrayList new出來,預設的容量到底是0還是10 ?

這種問題存在疑惑嗎?   如果你存在? 看完這篇你就沒疑惑了 。

這一篇結合源碼還有小代碼例子, 還有我的唠叨,我們還是一貫作風,學知識,跟着我,隻學一遍,忘不掉!

正文

不多說,開整:

JDK 1.8

第一行代碼,new一個ArrayList出來 :  

List<Integer> testList = new ArrayList<>();

然後點進去看源碼, 跟着我思路來,我們一起玩一玩這個ArrayList :

草圖:

Java ArrayList new出來,預設的容量到底是0還是10 ?

 如果耐心看完這個圖,大家應該其實心裡面對于前文提到的問題已經有一些結果了,

①arrayList 底層是個 數組, Object[] elementData ;

②size是 這個arrayList 的 底層數組 Object[] elementData 包含的元素 ,記住了是包含,而不是 這個數組的 length (length是注意點了,數組的length其實說白了就是所謂的容量);

③其餘就是2個空的數組,具體在哪裡被調用被使用,源碼裡面随便點一下就可以看到;

④ DEFAULT_CAPACITY 這個變量的注釋,有點小怪,預設初始容量 ,但是記住,我們以1.8源碼為準,眼見為實 。因為可以看到 :

Java ArrayList new出來,預設的容量到底是0還是10 ?

 第一句話: ArrayList的容量是該數組緩沖區的長度(上文已經說到了)。

第二句話,如果一個空的ArrayList 被第一次add的時候,  DEFAULT_CAPACITY=10這個值會被用上。

是以到了這裡, 再看一下new的時候調用的初始化構造函數,我們基本上就 心無任何疑惑了:

Java ArrayList new出來,預設的容量到底是0還是10 ?

 一個空的數組,那它的length就是 這個arrayList的 容量, 是多少? 顯然是 0 .

證據,我們直接反射拿出來這個elementData數組,就是要看它的length: 

public class DoTest {


    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

        List<Integer> testList = new ArrayList<>();
        Class<ArrayList> arrayListClass = ArrayList.class;
        Field field = arrayListClass.getDeclaredField("elementData");
        field.setAccessible(true);
        Object[] object1 = (Object[]) field.get(testList);
        //傳回目前ArrayList執行個體的容量值
        System.out.println("這時候容量是多少:" + object1.length);
        
    }
}      

運作結果: 

Java ArrayList new出來,預設的容量到底是0還是10 ?

是以結論一 核實: 

jdk 1.8 , new 一個 arraylist ,初始化的容量是  0  .

那麼繼續,核實一下 什麼時候 容量 變成10 ?

根據源碼的注釋,寫着,如果是通過無參構造函數new 出來的arraylist (有參都直接指定容量了不多說了), 第一個元素 add進去的時候,容量會 賦予為  DEFAULT_CAPACITY = 10; 

直接看下我們的例子代碼先  :

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

        List<Integer> testList = new ArrayList<>();
        Class<ArrayList> arrayListClass = ArrayList.class;
        Field field = arrayListClass.getDeclaredField("elementData");
        field.setAccessible(true);
        Object[] object1 = (Object[]) field.get(testList);
        //傳回目前ArrayList執行個體的容量值
        System.out.println("這時候容量是多少:" + object1.length);

        testList.add(100);
        Object[] object2 = (Object[]) field.get(testList);
        System.out.println("第一個值add完了之後,這時候容量是多少:" + object2.length);
        
    }
}      
Java ArrayList new出來,預設的容量到底是0還是10 ?

 運作結果:

Java ArrayList new出來,預設的容量到底是0還是10 ?

此時雖然可以下結論,但是我們再結合源碼看看,到底怎麼變成10的 :

第一小段代碼:

Java ArrayList new出來,預設的容量到底是0還是10 ?

 按照我們第一次add, size肯定是0了, 0+1 =1 ,是以 ensureCapacityInternal 這個函數傳入的是 1 ;

第二段小代碼:

Java ArrayList new出來,預設的容量到底是0還是10 ?

DEFAULTCAPACITY_EMPTY_ELEMENTDATA

,顯然我們new出來的,就是等于的:

Java ArrayList new出來,預設的容量到底是0還是10 ?

 這時候觸發的是 Match.max比較, 10和 1比較最大值,那當然是10 了 。

是以 ensureExplicitCapacity 函數被調用,傳入的 參數值是10 ;

第四段小代碼:

Java ArrayList new出來,預設的容量到底是0還是10 ?

可以看到, 擴容函數被觸發了, grow(10) ,看到這裡應該知道這個10容量其實就是第一次add的時候,擴容函數觸發賦予的容量值 10 ;

最後, 順便看看擴容函數  grow :

Java ArrayList new出來,預設的容量到底是0還是10 ?

 代碼非常簡單:

核心的幾個小代碼,我們一起看看 :

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

新的容量 等于  舊的 容量 + 舊的容量的一半, 那麼也就是 變成舊的容量的 1.5倍 :

Java ArrayList new出來,預設的容量到底是0還是10 ?

然後就是兩個if判斷了 ,

就拿我們的第一個add觸發擴容來說, 這時候傳入的 minCapacity是 10 ,而newCapacity=0+0的一半還是0,是以觸發的是  newCapacity =10 ;

elementData = Arrays.copyOf(elementData, newCapacity);  容量就變成10了~

if (newCapacity - minCapacity < 0) newCapacity = minCapacity;

另外一個if ,

if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity);

也就是當計算出來的newCapacity ,比最多允許的容量值還大,怎麼處理? 答案是,最大就給最大值。

Java ArrayList new出來,預設的容量到底是0還是10 ?

沒完, 最大值是多少?  源碼也有說 :

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

 為什麼需要 -8 ? 

注釋上寫的明明白白(預留了一些空間 存自己的東西):