ArrayList是在實際項目中一個很是經常使用的類,今天咱們經過源碼來了解一下ArrayList的本質java
//默認容量
private static final int DEFAULT_CAPACITY = 10;
//使用有參構造建立ArrayList的時候,若是size=0那麼elementData就會指向這個數組,或者調用trimToSize(0)方法也會指向這個空數組
private static final Object[] EMPTY_ELEMENTDATA = {};
//只有使用無參構造的時候纔會將elementData指向這個空數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//內部的元素數組,咱們使用get()方法其實就是從其中取出元素
transient Object[] elementData; // non-private to simplify nested class access
//ArrayList的長度,默認爲0
private int size;
//ArrayList的臨界值,若是下一次擴容的數值大於這個數值,那麼將elementData擴容到數組的最大值也就是0x7fffffff,若是最小須要的容量已經大於0x7fffffff那麼則拋出OOM異常
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
複製代碼
咱們要使用ArrayList一定要先new一個出來,如今咱們來看看new 到底作了寫什麼.算法
ArrayList<Object> arrayList = new ArrayList<>();
複製代碼
在咱們調用這樣一個空參構造的時候,ArrayList實際上幫咱們建立了一個空的數組,口說無憑,能夠來看看數組
/** * 構造一個空list而且初始化容量爲10(若是隻是單純的new實際上並無初始化容量) * Constructs an empty list with an initial capacity of ten. */
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
複製代碼
而這個 DEFAULTCAPACITY_EMPTY_ELEMENTDATA是什麼呢?ui
/** * 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 = {};
複製代碼
是的,他就是一個長度爲0的Object的對象數組. 這個是一個 默認的靜態被final修飾的的空數組實例,每個array list實例被new出來一開始都共享這個空數組實例.this
當咱們調用這兩個方法中的其中一個方法的時候,若是 initialCapacity==0或者c.size()==0那麼內部的element將會指向EMPTY_ELEMENTDATAspa
用一個場景來解釋這個問題code
在咱們建立ArrayList 的時候,若是使用ArrayList<>(int initialCapacity)指定初始化容量的方式來建立,這時候傳參是0那麼,ArrayList內部的容器指向的就是這個EMPTY_ELEMENTDATAcdn
在執行add方法的時候,若是是使用無參構造的方式建立的ArrayList 那麼就會直接初始化其容量爲10.對象
若是是使用有參構造的方式建立的ArrayList那麼就會執行正常的擴容方式blog
說白了就是,DEFAULTCAPACITY_EMPTY_ELEMENTDATA就是一個標記,用來區分ArrayList是否是無參構造建立的ArrayList
當咱們添加元素的時候只須要調用add方法就好了,可是你知道其背後到底執行了哪些動做嗎?讓咱們接着往下看吧!
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
複製代碼
咱們來看看流程
看了流程以後,你可能會有諸多問題.
究竟是怎麼計算擴容的容量的?
添加元素是怎麼添加的?
此處以**void add(E e)**爲例
當咱們添加一個元素的時候,若是這個元素是經過無參構造建立的(爲了避免讓思路變得更復雜,此處只針對void add(E e)方法添加元素的容量計算),那麼就將其容量初始化爲 DEFAULT_CAPACITY,也就是10(還記得開始咱們介紹了其內部的變量嗎,就是那個DEFAULT_CAPACITY)
看起來這樣作就足夠了,可是java爲了不溢出,又作了一層處理
新容量= 原來的容量+原來的容量/2 這塊有兩層判斷,
newCapacity-minCapacity<0 newCapacity-MAX_ARRAY_SIZE>0 (同newCapacity-Integer.MAX_VALUE - 8>0 )
第二個其實還想得通當超過最大數組長度的時候就將其擴展到Integer.MAX_VALUE
那第一個新的容量爲何會小於最小的容量呢?
其實是由於Integer超過最大範圍再加會溢出直接變爲-2^32.
從新建立一個新的數組,將其靠拷貝
System.arraycopy()