1. 程式人生 > >深入學習JDK原始碼系列之、ArrayList

深入學習JDK原始碼系列之、ArrayList

## 前言 JDK原始碼解析系列文章,都是基於JDK8分析的,雖然JDK15馬上要出來了,但是JDK8我還不會,我... ## 類圖 ![](https://img.iisheng.cn/array-list-diagram.png) - 實現了`RandomAccess`介面,可以隨機訪問 - 實現了`Cloneable`介面,可以克隆 - 實現了`Serializable`介面,可以序列化、反序列化 - 實現了`List`介面,是`List`的實現類之一 - 實現了`Collection`介面,是`Java Collections Framework`成員之一 - 實現了`Iterable`介面,可以使用`for-each`迭代 ## 屬性 ```Java // 序列化版本UID private static final long serialVersionUID = 8683452581122892189L; /** * 預設的初始容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 用於空例項的共享空陣列例項 * new ArrayList(0); */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 用於提供預設大小的例項的共享空陣列例項 * new ArrayList(); */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 儲存ArrayList元素的陣列緩衝區 * ArrayList的容量,是陣列的長度 * * non-private to simplify nested class access */ transient Object[] elementData; /** * ArrayList中元素的數量 */ private int size; ``` > 小朋友,你四否有很多問號? 1. 為什麼空例項預設陣列有的時候是`EMPTY_ELEMENTDATA`,而又有的時候是`DEFAULTCAPACITY_EMPTY_ELEMENTDATA` 2. 為什麼`elementData`要用`transient`修飾? 3. 為什麼`elementData`沒有被`private`修飾?難道正如註釋所寫的**non-private to simplify nested class access** > 帶著問題,我們繼續往下看。 ## 構造方法 ### 帶初始容量的構造方法 ```Java /** * 帶一個初始容量引數的構造方法 * * @param initialCapacity 初始容量 * @throws 如果初始容量非法就丟擲 * IllegalArgumentException */ 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); } } ``` - 如果`initialCapacity > 0`,就建立一個新的長度是`initialCapacity`的陣列 - 如果`initialCapacity == 0`,就使用EMPTY_ELEMENTDATA - 其他情況,`initialCapacity`不合法,丟擲異常 ### 無參構造方法 ```Java /** * 無參構造方法 將elementData 賦值為 * DEFAULTCAPACITY_EMPTY_ELEMENTDATA */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } ``` ### 帶一個集合引數的構造方法 ```Java /** * 帶一個集合引數的構造方法 * * @param c 集合,代表集合中的元素會被放到list中 * @throws 如果集合為空,丟擲NullPointerException */ public ArrayList(Collection c) { elementData = c.toArray(); // 如果 size != 0 if ((size = elementData.length) != 0) { // c.toArray 可能不正確的,不返回 Object[] // https://bugs.openjdk.java.net/browse/JDK-6260652 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf( elementData, size, Object[].class); } else { // size == 0 // 將EMPTY_ELEMENTDATA 賦值給 elementData this.elementData = EMPTY_ELEMENTDATA; } } ``` - 使用將集合轉換為陣列的方法 - 為了防止`c.toArray()`方法不正確的執行,導致沒有返回`Object[]`,特殊做了處理 - 如果陣列大小等於`0`,則使用 `EMPTY_ELEMENTDATA` > 那麼問題來了,什麼情況下`c.toArray()`會不返回`Object[]`呢? ```Java public static void main(String[] args) { List