public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { /** * 系列化ID. */ private static final long serialVersionUID = 8683452581122892189L; /** * 默認初始化容量. */ private static final int DEFAULT_CAPACITY = 10; /** * 用於空實例的共享空數組實例. */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 共享的空數組實例,用於默認大小的空實例。咱們將此與EMPTY_ELEMENTDATA區別開來, 以瞭解添加第一個元素時須要膨脹多少。 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 存儲ArrayList的元素的數組緩衝區。 ArrayList的容量是此數組緩衝區的長度。添加第 一個元素時,任何具備elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空 ArrayList都將擴展爲DEFAULT_CAPACITY。 */ transient Object[] elementData; /** * ArrayList的大小(它包含的元素數). * * @serial */ private int size;
以上屬性註釋都已經被翻譯成中文,經過這些註釋,咱們大概能瞭解到的一些有價值的信息java
ArrayList底層數據結構是一個Object數組數組
ArrayList的默認初始化容量爲10數據結構
一個空的ArrayList集合在添加第一個元素時被擴容爲10dom
ArrayList的大小是經過一個名爲size的int變量存儲的函數
源碼繼續往下看,先看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); } } /** * 經過這裏能夠看出,當調用ArrayList的無參構造函數時,這個ArrayList的Object數組被初始化爲 DEFAULTCAPACITY_EMPTY_ELEMENTDATA=10 */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
能夠看到ArrayList一共有三個構造函數,一個無參構造,兩個有參構造。this
當咱們在建立一個Arraylist集合時,若是不指定容量,也就是調用無參構造函數,那麼這個Arraylist會被初始化爲10.翻譯
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
另外注意到另外兩個有參構造,一個參數爲int initialCapacity
,也就是咱們指定的初始化容量,這裏對這個initialCapacity進行了一些簡單的驗證code
public ArrayList(int initialCapacity) { if (initialCapacity > 0) {//initialCapacity > 0 this.elementData = new Object[initialCapacity];//將一個容量爲initialCapacity的新Object數組賦給elementData。 } else if (initialCapacity == 0) {//initialCapacity==0 this.elementData = EMPTY_ELEMENTDATA;//將EMPTY_ELEMENTDATA這個空object賦給elementData } else {//其餘狀況,也就是小於0,直接拋異常 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
另外一個有參構造ci
public ArrayList(Collection<? extends E> c) { elementData = c.toArray();//將Collection集合轉化爲數組,而後賦給elementData這個object數組 if ((size = elementData.length) != 0) {//若是這個集合長度不爲0 // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class)//若是集合轉化後的數組不是Object數組 elementData = Arrays.copyOf(elementData, size, Object[].class);//轉化爲Object數組 } else {//其餘狀況,也就是elementData的長度爲0嘛 // 替換爲EMPTY_ELEMENTDATA空的數組 this.elementData = EMPTY_ELEMENTDATA; } }
能夠看到這個構造函數,它是直接把一個Collection丟了進去,這也就是說,在new一個ArrayList時咱們能夠把一個Collection集合放到參數列表中。
接下來再來看ArrayList的add方法
/** * 將元素添加到列表的末尾 * * @param e 要被追加到list中的元素 * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e;//將元素e添加到數組中,下標爲size++,其實也就是size,而後添加後size+1, return true; }
這裏就兩行代碼,調用ensureCapacityInternal
這個方法,而且參數爲size+1。點進去看下ensureCapacityInternal()
這個方法
/* 經過這個方法咱們能夠看出,當咱們第一次調用add方法的時候,elementData數組的size爲0,那麼size+1就爲1,因此minCapacity也爲1,這裏先經過一個if判斷,判斷minCapacity是否是一個空的object數組,若是是的話,minCapacity就取DEFAULT_CAPACITY和minCapacity的最大值,也就是10嘛 */ private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //判斷完以後進入了這個方法,同時參數爲minCapacity,若是是第一次調用add方法的話參數爲minCapacity就是默認大小10,不是第一次調用的話,就是size+1, ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; //這個grow()就是擴容函數,如今minCapacity的話,仍是同樣的分析,若是第一次調用add方法的話就是10,同時elementData.length爲0,不是第一次調用的話minCapacity就是size+1,elementData.length也就是數組的長度爲size if (minCapacity - elementData.length > 0) grow(minCapacity); }
讀完這一段源碼,能夠得出如下結論
接下來咱們再來看下grow方法,瞭解一些Arraylist究竟是怎麼樣擴容的
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); //若是數組當前長度+數組當前長度/2 < 數組當前元素個數+1 if (newCapacity - minCapacity < 0) //就把數組當前元素個數+1賦給newCapacity newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 最後咱們能夠看到,這裏進行了一個複製操做,將elementData裏面的元素,複製到一個新的長度爲newCapacity的Object數組,而後再把它賦給elementData elementData = Arrays.copyOf(elementData, newCapacity); }
這段代碼應該很清晰吧,grow方法傳進來的參數就是上面minCapacity,第一次調用add方法時是10,其餘時候調用時是size+1(當前存儲元素個數+1)
這裏簡單來講就是將elementData當前長度給oldCapacity,而後newCapacity = oldCapacity + oldCapacity >> 1(左移操做,至關於除於2),若是oldCapacity = 10的話,newCapacity = 10 +(10/2),也就是15。經過以上代碼,不難看出,ArrayList的擴容方法實際上就是將底層Object數組複製到了一個新的長度更長的數組裏面去,而這個新數組的長度是原來的數組長度+原來數組長度的二分之一
,其實就能夠說了擴容了1.5倍。
經過對以上源碼進行分析,咱們能夠得出如下結論了
總結:
elementData.length+1
個元素時會發生擴容,好比數組長度爲10,在添加第11個元素時擴容原來數組長度+原來數組長度左移1位
完成,而不是直接經過乘法