Java API學習(一) ArrayList源碼學習

ArrayList在日常用的還挺多的,用起來十分舒服,順手。這裏來學習一下它的源碼。java

類定義

下面是類的定義:數組

1 public class ArrayList<E> extends AbstractList<E>
2         implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
3 
4

實現的接口還挺多的。dom

類屬性

首先來看下一ArrayList的幾個屬性:學習

 

1. DEFAULT_CAPACITY:初始容量this

1 private static final int DEFAULT_CAPACITY = 10;

DEFAULT_CAPACITY,是ArrayList的初始容量,有意思是它使用的時機。spa

2. EMPTY_ELEMENTDATA:共享的空數組.net

1 private static final Object[] EMPTY_ELEMENTDATA = {};

英文註釋是:"Shared empty array instance used for empty instances."。這個看上去仍是很好理解的,可是下面還有一個屬性也是空數組。code

3. DEFAULTCAPACITY_EMPTY_ELEMENTDATA:默認容量的空數組對象

好奇怪,用一個EMPTY_ELEMENTDATA不就能夠了麼,爲何還要用一個DEFAULTCAPACITY_EMPTY_ELEMENTDATA呢?當咱們使用new ArrayList()的時候就會發現這個空數組實例排上用場了:blog

1 public ArrayList() {
2     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
3 }

這個方法的英文註釋是:"Constructs an empty list with an initial capacity of ten."。可是這裏其實就把這個空的數組對象DEFAULTCAPACITY_EMPTY_ELEMENTDATA給了elementData,並無實例化額外的對象數組。

4. elementData:實際元素所在的數組

1 transient Object[] elementData; // non-private to simplify nested class access

elementData纔是元素真正存放的地方,這裏不明白的是爲何要用transient關鍵字。

這個數組緩衝區是ArrayList存儲元素的地方。ArrayList的容量正是這個數組緩衝區的長度。任何elementData爲DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList會在添加第一個元素的時候,將容量擴充到DEFAULT_CAPACITY(目前是10)。 

5. size:數組中元素的長度

1 private int size;

這裏的size並非elementData數組的長度,而是這個數組真正包含的元素的個數(這個個數其實有待商榷,後面會講到)。

構造方法

在ArrayList中一共有3個構造方法:

1 // 給定初始容量
2 public ArrayList(int initialCapacity);
3 
4 // 空參構造方法
5 public ArrayList();
6 
7 // 從其餘集合類中構造
8 public ArrayList(Collection<? extends E> c);

 1. 給定初始容量的constructor

 1 public ArrayList(int initialCapacity) {
 2     if (initialCapacity > 0) {
 3         this.elementData = new Object[initialCapacity];
 4     } else if (initialCapacity == 0) {
 5         this.elementData = EMPTY_ELEMENTDATA;
 6     } else {
 7         throw new IllegalArgumentException("Illegal Capacity: "+
 8                                            initialCapacity);
 9     }
10 }

邏輯以下:

  • initialCapacity > 0爲真時,建立一個大小爲initialCapacity的空數組,並將引用賦給elementData
  • initialCapacity == 0爲真時,把以前的空數組EMPTY_ELEMENTDATAelementData
  • initialCapacity < 0爲真時,直接拋出IllegalArgumentException異常。

惟一一點是爲啥這個時候要用EMPTY_ELEMENTDATA了,而不是繼續用原來的DEFAULTCAPACITY_EMPTY_ELEMENTDATA了。

2. 空參構造方法

1 public ArrayList() {
2     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
3 }

這個就比較簡單了,和上面對比的是,這個時候爲啥要用DEFAULTCAPACITY_EMPTY_ELEMENTDATA

問題來了:new ArrayList(0)和new ArrayList()有啥不一樣呢?

惟一的不一樣就在於內部數組用的不是同一個,雖然它們都是空的。

 

3. 從集合類中構造

 1 public ArrayList(Collection<? extends E> c) {
 2     elementData = c.toArray();   // 注意, 這個時候ArrayList中元素的順序取決於toArray
 3     if ((size = elementData.length) != 0) {
 4         // c.toArray might (incorrectly) not return Object[] (see 6260652)
 5         if (elementData.getClass() != Object[].class)
 6             elementData = Arrays.copyOf(elementData, size, Object[].class);
 7     } else {
 8         // replace with empty array.
 9         this.elementData = EMPTY_ELEMENTDATA;
10     }
11 }

這裏有兩個地方須要注意下:

  • 集合轉ArrayList以後元素的順序是由集合的toArray方法所決定的;
  • toArray可能會不正確地返回數組對象Object[].class, see 6260652。 

 Collection接口的toArray方法依賴於實現類中的具體實現,有時候ArrayList中的順序對咱們來講仍是挺重要的。而後在來看一下,這個官方bug,我在網上查了一下,發現這篇寫的不錯:https://blog.csdn.net/gulu_gulu_jp/article/details/51457492

新增元素的方法

新增元素的方法是ArrayList中最值得關注的,它提供了兩種add方法:

  • 沒有index的add方法,即在內部數組的末尾添加一個元素;
  • 在給定的index處插入元素,index右邊的元素會後移。

沒有index的add方法

1 public boolean add(E e) {
2     ensureCapacityInternal(size + 1);  // Increments modCount!!
3     elementData[size++] = e;
4     return true;
5 }

ensureCapacityInternal方法在ArrayList中不少地方都用到了,很是關鍵的方法。

當插入新元素所需的最小capacity要比內部數組的長度大的時候,就要擴容了,如今原來的基礎之上擴容50%,若是新的capacity比最小的capacity還要小的話,直接用所需最小的capacity做爲capacity。

有index的方法

在這種狀況下是在ArrayList的某個位置上插入一個元素,而後把index後邊的元素集體往右移一位。須要注意的問題是,index的範圍是有限制的,必須在[0, size)之間,那麼這中檢查是爲了避免讓ArrayList之間出現空洞。

1 public void add(int index, E element) {
2     rangeCheckForAdd(index);           // 返回檢查
3     ensureCapacityInternal(size + 1);  // 擴容
4     System.arraycopy(elementData, index, elementData, index + 1,
5                  size - index);        // 右移元素
6     elementData[index] = element;      // 插入新元素
7     size++;
8 }

ArrayList中的內部模型 

理解了ArrayList的內部模型的話,其實看不看源碼感受關係不大。

其餘方法

其餘方法我以爲還挺常規的,沒有太多好說的,就是System.arraycopy用得還挺多的,專門用於複製數組。

 


以上~

相關文章
相關標籤/搜索