ArrayList源碼解析-1.8
-
數組介紹
在java中當創建數組時會在內存中劃分一塊連續的內存,然後將數據順序存儲在連續的內存中。當需要讀取數組中的數據時需要提供數組中的索引。在java中只有相同類型的數據纔可以一起存儲到數組中。
因爲數組在存儲數據是按順序存儲的,存儲數據的內存也是連續的,所以他的特點就是尋址讀取數據比較容易,插入和刪除比較困難。
-
ArrayList源碼分析
-
構造方法,三種類型的構造方法
// 默認初始化容量 private static final int DEFAULT_CAPACITY = 10; // 空對象數組 private static final Object[] EMPTY_ELEMENTDATA = {}; //缺省空對象數組 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // ArrayList的大小 包含elementData數量 private int size; transient Object[] elementData; // 無參構造函數 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 有初始容量的構造方法 public ArrayList(int initialCapacity) { // 如果傳入的容量值大於0 new一個object數組,大小爲initialCapacity if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // 官方bug // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) // 創建了一個object數組 長度爲size 內容時elementData elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // size不等於零,初始化一個空數據對象 replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
-
Add方法
/** * Appends the specified element to the end of this list. * 追加這個指定得元素到列表的末尾 * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { // 擴容機制 ensureCapacityInternal(size + 1); // Increments modCount!! // 數組長度+1,把元素e放到最後 elementData[size++] = e; return true; } /** * Inserts the specified element at the specified position in this * list. Shifts the element currently at that position (if any) and * any subsequent elements to the right (adds one to their indices). *將指定的元素插入此列表中的指定位置。將當前在該位置的元素(如果有的話)和任何後續元素向右移動(向其索引添加一個)。 * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { // 相當於健康檢查,查看數據元素是否越界 rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! //index都是從0開始的 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } /** * A version of rangeCheck used by add and addAll. */ private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
-
addAll()
public boolean addAll(Collection<? extends E> c) { // 轉換爲數組 Object[] a = c.toArray(); // 需要插入到列表的數據的長度 int numNew = a.length; // 看是否需要擴容 當前容量大於size + numNew 就不需要 ensureCapacityInternal(size + numNew 就不需要); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; } /** * @param src the source array.源數組 * @param srcPos starting position in the source array.源數組中的起始位置 * @param dest the destination array.目標數組 * @param destPos starting position in the destination data.目標數組中的起始位置 * @param length the number of array elements to be copied.要複製的數組元素數量 * @exception IndexOutOfBoundsException if copying would cause * access of data outside array bounds. * @exception ArrayStoreException if an element in the <code>src</code> * array could not be stored into the <code>dest</code> array * because of a type mismatch. * @exception NullPointerException if either <code>src</code> or * <code>dest</code> is <code>null</code>. */ public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount int numMoved = size - index; if (numMoved > 0){ // 舉例說明: // 目標數組數組[1,2,3,4],index=2 源數組[5,6] 生成[1,2,5,6,3,4] // 此處目標數組爲[1,2, 3,4, 3,4] System.arraycopy(elementData, index, elementData, index + numNew, numMoved); } // 源數組[5,6] 目標數組[1,2,3,4,3,4]-->[1,2,5,6,3,4] System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; }
-
擴容機制
// 確保內部容量 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } // 計算容量 // 傳入對象數組和最小容量,minCapacity = size+1 這個地方可以看add方法 private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 對比默認的容量10,誰大返回誰 return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0){ grow(minCapacity); } } /** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * 增加容量以確保它至少可以容納最小容量參數指定的元素數。 * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; // 假定oldCapacity = 10,新增一個數據,那麼minCapacity = 11 // 11右移1位,二進制爲0101,十進制爲5,minca擴容後的newCapacity = 15.爲oldCapacity的1.5倍。 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: // minCapacity通常接近於size,所以這是一個優勢: // 那種角度來說是一種優勢? elementData = Arrays.copyOf(elementData, newCapacity); } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 巨大的容量,假設生成的newCapacity比MAX_ARRAY_SIZE還大,但是不能超過Integer.MAX_VALUE最大值,否則拋出內存溢出異常。 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
-
刪除方法
//ArrayIndexOutOfBoundsException,如果下標越界 private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } public E remove(int index) { rangeCheck(index); // modcount記錄操作次數 modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) //[1,2,3,4] index+1=3 [1,2,3,4] 2 1 -->[1,2,4,4] System.arraycopy(elementData, index+1, elementData, index, numMoved); // [1,2,4] elementData[--size] = null; // clear to let GC do its work return oldValue; } 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; } // 這個fastremove和remove(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 } public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); // 批量刪除 return batchRemove(c, false); } private boolean batchRemove(Collection<?> c, boolean complement) { // 獲取當前的列表元素 final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++) // 當前complement爲false時:排除掉c中的數據 // 當complement爲true時:交集 if (c.contains(elementData[r]) == complement) // 其實這個地方就是把要刪除的元素去掉了。 elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. // 避免c.contains拋異常 // r什麼情況下會不等於size呢?上面for循環size的嘛???? // 底下的代碼有待考究 if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } // w等於size的時候,相當於不需要刪除任何元素,直接return modified false if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++){ // 清空多餘的元素 elementData[i] = null; } modCount += size - w; size = w; modified = true; } } return modified; } // 清空所有數據,easy public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
- retainAll()
// 查詢集合的交集
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
// 和removeall一樣的方法complement爲true的時候 查詢交集
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
- indexOf() lastIndexOf()
public int indexOf(Object o) {
// 之所以這樣處理是應爲ArrayList是允許有null值的,避免空指針異常
// 爲什麼支持null?因爲從源碼看存null不會有錯,所有的null值都被當爲正常值處理
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
//和上面唯一的不通就是此處循環爲i--
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
- sort 排序
@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
// 調用Arrays工具類進行排序
public static <T> void sort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> c) {
if (c == null) {
sort(a, fromIndex, toIndex);
} else {
rangeCheck(a.length, fromIndex, toIndex);
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex, c);
else
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
}
}