本文采用的是jdk1.8,分析ArrayList常用的方法源碼;如有錯誤,請指出,謝謝
一,ArrayList的關係圖
在我們日常開發階段,ArrayList是我們用的非常非常多的一個集合,帶來了很大的便利,下面開始分析ArrayList的源碼
二,源碼分析
2.1屬性分析
從ArrayList的屬性,我們可以很清楚的看出:ArrayList的底層就是一個數組的形式,ArrayList中有擴容的概念,正式因爲有擴容,所有它能實現動態增長
2.2 構造方法
2.3 add方法
add()方法是我們常用的方法,可以說是ArrayList比較重要的方法了,下面我們來看看:
2.3.1 add(E e)
步驟:
- 檢查是否需要擴容
- 插入元素
首先先看看這個方法
public boolean add(E e) {
//確定list的容量,嘗試容量加1
ensureCapacityInternal(size + 1); // Increments modCount!!
//添加元素
elementData[size++] = e;
return true;
}
這個方法主要就是幹兩件事:
- 確定list的容量,嘗試容量+1,看有沒有擴容的必要
- 添加元素
接下來進入ensureCapacityInternal()方法,看看容量的的添加過程
隨後調用ensureExplicitCapacity()來確定明確的容量,我們也來看看這個方法是怎麼實現的:
接下來看看grow()對數組的擴容過程
進入copyOf()方法看看是如何移動數組的
我們再進入arraycopy()裏看看
該方法帶有native修飾符,就可以知道是C/C++去寫的,並非java來實現的,總的來說arraycopy()是一個比較高效可靠的方法
到目前爲止,我們可以知道add(E e)的基本實現了:
>>首先去檢查一下數組的容量是否足夠
>>>>足夠,直接添加元素
>>>>不足夠,擴容數組
>>>>>>擴容都原來的1.5倍
>>>>>>第一次擴容後,如果容量還是小於minCapacity,就將容量擴充爲minCapacity
2.3.2 add(int index, E element)
步驟:
- 檢查角標
- 檢查是否需要擴容
- 插入元素
下面這個是插入的實現:
2.4 get()
步驟:
- 檢查角標
- 返回元素
接下來我們看看rangeCheck()和elementData()兩個方法:
2.5 set(int index, E element)
步驟:
- 檢查角標
- 替代元素
- 返回舊值
2.6 remove(int index)
步驟
- 檢查角標
- 計算要移動的個數,並移動
- 將最後一個元素設爲null(刪除),讓gc進行回收
2.7 細節說明
- ArrayList是基於動態數組實現的,在增刪時候,需要數組的拷貝複製。
- ArrayList的默認初始化容量是10,每次擴容時候增加原先容量的一半,也就是變爲原來的1.5倍
- 刪除元素時不會減少容量,若希望減少容量則調用trimToSize()
- 它不是線程安全的。它能存放null值。