這一篇開始集合的總結,通過前兩篇文章(fail-fast 以及 Spliterator)的鋪墊,咱們能更快的進入集合類的學習。本篇是集合類的開篇,也是比較簡單的一篇。此次咱們主要來看看ArrayList類的實現。看看他是如何存儲元素以及擴容的。算法
首先,咱們來看看ArrayList繼承了啥,實現了啥數組
這裏咱們不對AbstractList進行講解,不過就是一些List的基本操做。咱們重點看一下RandomAccess。dom
查看RandomAccess的源碼:性能
咱們發現他什麼都沒幹,那麼這個接口是幹什麼的呢? 其實,從名字咱們也能猜出來他是幹啥的RandomAccess 即隨機訪問,源碼中是這麼介紹他的學習
一個標記接口,List實現它表示本身支持快速的(一般是恆定時間)隨機訪問。這個接口的主要目的就是容許算法去提供一個更好的執行性能當決定使用隨機或者順序訪問的時候。3d
上面的隨機訪問即便用索引 index去訪問,順序訪問則是使用Iterator這樣迭代的方法去訪問。cdn
因此當算法去決定是否是使用隨機訪問比順序訪問的好的時候就能夠用 instanceof RandomAccess 去判斷。對象
上面咱們說這個ArrayList隨機訪問的性能好,那麼爲何隨機訪問性能好呢? 咱們來看看ArrayList中的幾個屬性。blog
意思就是調用這個方法後,elementData的數組的長度就會等於size的大小,即把數組的大小調整爲存儲當前數量元素實際須要的大小。繼承
通過上面的分析,咱們得出了ArrayList的存儲結構是一個數組的形式
對於添加來講不過就是add方法,set方法。咱們實際看一下代碼:
咱們先無論ensureCapacityInternal這個方法,這個是擴容機制的開始方法,下面咱們會再提。 其實對於插入來講就是對數組的操做,有意思的是,在add(int index,E element)中使用了System.arraycopy方法來對數組進行移位操做。這是一個淺複製,有興趣額的同窗本身查查看吧。 刪除操做其實都同樣,就不作贅述了。
ArrayList的擴容機制其實挺簡單的,咱們先從代碼入手看看,他是怎麼完成這個擴容的。上面提到ensureCapacityInternal方法時擴容的開始,其實在每個往elementData裏面添加元素的方法中都先調用了這個方法,參數是增長當前元素的數量加上須要添加元素的數量。即ArrayList在添加元素的時候會檢查是否須要擴容。咱們先看看這個方法:
咱們能夠看到,這個方法先判斷了一下elementData是否等於DEFAULTCAPACITY_EMPTY_ELEMENTDATA,即咱們上面提到的使用new ArrayList();生成的ArrayList對象中elementData賦予的值,也就是檢查一下,這個ArrayList是否是默認容量如今是DEFAULT_CAPACITY。
這個minCapacity的含義就是添加某個多多個元素後,elementData最小的長度。
以後這個方法又調用了ensureExplicitCapacity方法,咱們如今看一下這個方法的內容:
modCount做用於快速失敗機制,若是不瞭解能夠看一下這篇文章。
以後判斷了一下這個minCapacity的大小是否大於elementData的長度,即elementData的大小是否是已經不知足增長某個或者多個元素的要求了。
若是不知足則調用grow方法。如今就到了擴容的核心了,咱們先看一下grow方法的內容:
其實就是對應該擴容後elementData的大小進行判斷,默認增加爲原來大小的1.5倍。由於是使用位移的方法計算原來elementData長度的一半,因此有可能oldCapacity>>1的結果爲負數,這時候直接擴容爲須要的大小。後面的不解釋了,很簡單。
要注意一點,因爲elementData是數組,而數組的大小是不能改變的,因此擴容是從新建立了一個數組。