【Java集合】2 ArrayList

whynotyue 發表於 2020-10-18

Vector

Q:ArrayList 和 Vector 的區別?

  1. 都是基於動態陣列實現,支援隨機訪問,查詢快,增刪慢,因為要移動後續所有的元素,但 Vector 是執行緒安全的,ArrayList 不是執行緒安全的,效能更好;
  2. 底層使用物件陣列儲存資料,當陣列滿時,會自動擴容,建立新的陣列,並拷貝原有陣列資料,擴容後 ArrayList 容量增加 50%,Vector 增加一倍。

LinkedList

Q:ArrayList 和 LinkedList 的區別?

  1. 都不是執行緒安全的。
  2. ArrayList 基於動態陣列實現,支援隨機訪問,查詢快;LinkedList 基於雙向連結串列實現,只能順序訪問,查詢慢。
  3. ArrayList 快在定址,慢在要移動元素以及可能的擴容,所以越往後,不發生擴容時,效率越高;LinkedList 快在只需修改 Entry 的引用,慢在定址,所以越往前,效率越高;整體上,由於元素增刪的不確定性,以及可能的擴容,LinkedList 增刪快於 ArrayList。
  4. LinkedList 因為要存放元素、直接前驅和後繼,所以會佔用更多記憶體。

擴容機制

使用 add() 時,內部先呼叫 ensureCapacityInternal() ,傳入 size + 1,來檢查底層陣列 elementData 是否需要擴容。

public boolean add(E e) {
    ensureCapacityInternal(size + 1); 
    elementData[size++] = e;
    return true;
}
// JDK11 移除了 ensureCapacityInternal() 和 ensureExplicitCapacity() 方法

在這個方法中,先判斷陣列 elementData 是否為空,如果為空,那麼 minCapacity 取預設容量 10 和 size + 1 中更大的那個,

然後呼叫 ensureExplicitCapacity() 。

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

它會先進行 modCount 自增,來記錄集合結構發生變化的次數,用於迭代的快速失敗;

然後判斷 minCapacity 是否大於陣列長度,如果是,就呼叫 grow(),進行擴容。

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

grow() 中,新容量為原來的 1.5 倍,如果還不夠,就使用它指定要擴容的大小 minCapacity,然後判斷 minCapacity 是否大於 MAX_ARRAY_SIZE,如果大於,新容量為 Integer.MAX_VALUE;最後呼叫 Arrays.copyOf() 拷貝原陣列資料,完成擴容。

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0)
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

ArrayList原始碼分析(擴容機制jdk8)