目錄
前言
ArrayList是可以動態增長和縮減的索引序列,他是基於數組實現的list類。
- 不同於數組,ArrayList可以自增減
- ArrayList支持隨機訪問,查詢效率高,增加、刪除效率低
- 非線程安全
原碼分析
接下來我們針對其原碼做以下分析:繼承關係、類中屬性、構造函數、核心方法 四個方面分析
AbstractList:抽象類封裝了通用的list集合操作
RandomAccess:標記接口,表明它們支持快速隨機訪問
Cloneable:支持接口,實現
Cloneable
接口,支持Object.clone()方法(CloneNotSupportedException
)java.io.Serializable:標記接口,支持序列化
繼承關係
類中屬性
- serialVersionUID:序列化編號
- DEFAULT_CAPACITY:集合的初始化容量
- DEFAULTCAPACITY_EMPTY_ELEMENTDATA:默認的空數組對象
- EMPTY_ELEMENTDATA:空數組對象
- MAX_ARRAY_SIZE:集合元素數組的最大值
- elementData:集合的元素數組對象
- size:集合的大小
- modCount:來源AbstractList,迭代器使用,多線程併發修改觸發fail-fast機制
備註:elementData arrayList底層是數組,實際元素存在數組elementData;
modCount記錄當前集合被修改的次數,當我們遍歷集合時調用集合的add(),remove()等方法時,modecount值會被改變;而迭代器記錄的還是原來的還是遍歷之前的值,不一致則說明多個線程再同時操作集合,爲了保證結果的準確性拋異常
ConcurrentModificationException
。
構造函數
核心方法
接下來我們從初始化、新增、修改、查詢、刪除分析下原碼
/**
* ArrayList數據結構
* ArrayList底層是數組,集合的操似對數組的操作
* . 主要結構成員:DEFAULT_CAPACITY、elementData、size ...
* . 集合操作流程(初始化、增、刪、改、查)
*/
@Test
public void testArrayList() {
//初始化
List list = new ArrayList();
//新增
list.add("a1");
log.info("添加元素a1到集合list:{}", list);
//修改
list.set(0, "a11");
log.info("修改位置爲0的集合元素list:{}", list);
//查詢
log.info("查詢位置0的集合元素:{}", list.get(0));
//刪除
list.remove(0);
log.info("刪除集合元素後:{}", list);
}
//初始化 List list = new ArrayList();
無參構造函數構建一個默認容量爲10的空集合;集合第一次添加元素方可同步默認容量;
//新增 list.add("a1");
List.add()會在集合數組的末尾添加元素E
- 確保添加元素後集合空間充足
- 計算集合保存元素需要空間,如果集合元素爲缺省空數組,在默認容量DEFAULT_CAPACITY = 10和size+1之間取最大值;否則集合需要空間爲size+1
- 集合修改次數modCount+1
- 判斷是否需要擴容:如果size+1>elementData.length,執行擴容方法grow()
- 數組末尾添加新元素
- 當前集合的size+1
ensureCapacityInternal()方法
calculateCapacity()方法
ensureExplicitCapacity()方法
grow()方法
//修改 list.set(0, "a11");
- 獲得索引的原元素
- 替換數組在當前索引的值爲新元素
- 返回原元素
//查詢 list.get(0) ;
//刪除 list.remove(0);
- 驗證刪除的索引位置是否越界
- 修改計數器+1
- 查詢當前修改位置的元素
- 計算需要移動的元素個數
- 索引之後的元素向前移動1位
- 集合的原最後位置賦值爲null
- 返回刪除的元素
總結
- ArrayList本質上是一個elementDate數組
- ArrayList集合的大小≠elementDate數組的長度
- ArrayList支持存放null
- ArrayList實現了RandomAccess,標記支持隨機訪問
- ArrayList由於底層是數組(固定長度),擴容或者縮容時會移動較多元素