Java 集合 ArrayList VS LinkedList VS Vector

更多 Java 集合類方面的文章,請參見文集《Java 集合類》


共同點:

  • 都實現了 List 接口
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

public class LinkedList<E> extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

public class Vector<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 都可以插入 null

基本區別:

  • 實現方式:

    • ArrayList 和 Vector 基于數組實現,可以隨機訪問,實現了 RandomAccess 接口
    • LinkedList 基于鏈表實現,不可隨機訪問,實現了 Deque 接口
  • 初始容量:

    • ArrayList 初始容量為 10
    • Vector 初始容量為 10
    • LinkedList 基于鏈表實現,初始容量為 0
  • 擴容方式:

    • ArrayList 數組容量不夠時,擴容 50% int newCapacity = oldCapacity + (oldCapacity >> 1);
    • Vector 數組容量不夠時,擴容 100%
    • LinkedList 基于鏈表實現,無需考慮擴容
  • 是否線程安全:

    • ArrayList 線程不安全
    • Vector 線程安全
    • LinkedList 線程不安全

ArrayList 的實現原理

構造

  • public ArrayList() 可以構造一個默認初始容量為 10 的空列表;
    • private static final int DEFAULT_CAPACITY = 10;
  • public ArrayList(int initialCapacity) 構造一個指定初始容量的空列表;
  • public ArrayList(Collection<? extends E> c) 構造一個包含指定 collection 的元素的列表,這些元素按照該 collection 的迭代器返回它們的順序排列的。

調整數組容量

每當向數組中添加元素時,都要去檢查添加后元素的個數是否會超出當前數組的長度,如果超出,數組將會進行擴容,以滿足添加數據的需求。
數組擴容有兩個方法:

  • 開發者可以通過一個 public 的方法 ensureCapacity(int minCapacity) 來增加 ArrayList 的容量:
public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}
  • 而在存儲元素等操作過程中,如果遇到容量不足,會調用 private 方法 private void ensureCapacityInternal(int minCapacity)
    實現:
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

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

    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
 * The maximum size of array to allocate.
 * Some VMs reserve some header words in an array.
 * Attempts to allocate larger arrays may result in
 * OutOfMemoryError: Requested array size exceeds VM limit
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
 * 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;
    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:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

數組的擴容操作的代價是很高的,因此在實際使用時,我們應該盡量避免數組容量的擴張。

  • 當我們可預知要保存的元素的多少時,要在構造 ArrayList 實例時,就指定其容量,以避免數組擴容的發生。
  • 或者根據實際需求,通過調用 ensureCapacity 方法來手動增加 ArrayList 實例的容量。

LinkedList 的實現原理

使用鏈表

private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

雙端鏈表

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

引用:
ArrayList 的實現原理
LinkedList 的實現原理

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容