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進行原始碼分析的文章~