1. 程式人生 > >JDK原始碼分析之ArrayList(二)

JDK原始碼分析之ArrayList(二)

ArrayList原始碼分析(二)

這裡是ArrayList的第二部分,介紹remove、clear、sublist、trimToSize、iterator、toArray等方法。

(多看看原始碼有利於對集合類使用的理解~)

remove方法

根據下標remove

public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

流程如下:

1)判斷索引有沒有越界

2)自增修改次數

3)將指定位置(index)上的元素儲存到oldValue

4)計算得到需要移動的元素數

5)使用System.arraycopy,將需要移動數向前移動一位

6)將最後一個數設為null(準備被垃圾回收器回收)

7)將原來的值oldValue返回

注意:呼叫這個方法不會縮減陣列的長度,只是將最後一個數組元素置空而已。

根據物件remove

public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

首先判斷移除的物件是否為null,則迴圈遍歷陣列,如果某一個下標對應的元素為null則使用fastRemove(index)進行移除,返回true;

如果要被移除的物件不為null,則迴圈遍歷,使用equals方法找到對應下標,也是使用fastRemove(index)進行移除,返回true;

下面介紹一下fastRemove(index):

private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

fastRemove實際上就是根據下標的remove方法的簡化版,沒有了返回值,也不需要進行下標是否越界的檢查

clear方法

public void clear() {
    modCount++;

    // clear to let GC do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

先是增加修改次數,然後迴圈遍歷將陣列中的每一個元素修改為null,最後將陣列的長度修改為0,這樣就達到了清除集合內所有元素的目的。

sublist方法

public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}

先是會對sublist傳入的引數進行檢查,然後返回一個其內部類sublist的一個例項。在該例項中的每一個方法都有checkForComodification();這是對其修改次數併發的檢測。簡單來說,如果修改了原始ArrayList的結構(’structurally modified’),自然會導致該SubList物件和原ArrayList物件的modCount不同。

所以,在使用sublist的時候要注意結構性的修改帶來的ConcurrentModificationException。

trimToSize方法

public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

ArrayList所說沒有用的值並不是null,而是ArrayList每次增長會預申請多一點空間,1.5倍+1,而不是兩倍
這樣就會出現當size() = 1000的時候,ArrayList已經申請了1200空間的情況
trimToSize 的作用只是去掉預留元素位置,就是刪除多餘的200,改為只申請1000,記憶體緊張的時候會用到.

iterator方法

public Iterator<E> iterator() {
    return new Itr();
}

在ArrayList中實現了iterator迭代器,便於集合的遍歷及操作。(具體詳見程式碼或後續對於迭代器的分析)

toArray()方法

public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

呼叫Arrays.copyOf將返回一個數組,陣列內容是size個elementData的元素,即拷貝elementData從0至size-1位置的元素到新陣列並返回。

toArray(T[] a)方法

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

如果傳入陣列的長度小於size,返回一個新的陣列,大小為size,型別與傳入陣列相同。所傳入陣列長度與size相等,則將elementData複製到傳入陣列中並返回傳入的陣列。若傳入陣列長度大於size,除了複製elementData外,還將把返回陣列的第size個元素置為空。

後續還會對集合類中的HashMap進行原始碼分析的文章~