1. 程式人生 > >ArrayLsit與Vector的區別

ArrayLsit與Vector的區別

ArrayList 和 Vector 類都是基於陣列實現的 List 類. ArrayList 和 Vector 封裝了一個動態的, 允許再分配的 Object[] 陣列. ArrayList 和 Vector 使用 initialCapacity 引數來設定該陣列的長度. 當向 ArrayLsit 和 Vector 陣列中新增元素超過改陣列的長度時, 在底層會自動將陣列進行擴容.

關於 ArrayList 和 Vector 的區別, 主要有這幾點:

(1) ArrayList 是執行緒不安全的, 當多個執行緒訪問同一個ArrayList 集合, 如果有超過一個執行緒修改了 ArrayList 集合, 則程式必須手動保證該集合的同步性.  Vector是執行緒安全的, Vector 類中的方法都有 synchronized 修飾, 所以 Vector 效能比 ArrayLsit 效能要差.

Vector 類的所有方法都是同步的, 可以由多個執行緒安全地訪問一個 Vector 物件. 但是在一個執行緒訪問 Vector 的話程式碼要在同步操作上耗費大量的時間.  ArrayList 不是同步的, 所以在不需要保證執行緒安全時建議使用 ArrayLsit.

(2) ArrayList 和 Vector 底層都是採用陣列來儲存元素的, 當陣列儲存空間不夠時, 兩個類對陣列擴容的方式是不一樣的.

(3)通過 Vector 的構造引數可以設定增量因子, 用於對Vector 底層陣列的擴容. 分析見 Vector 原始碼:

 protected Object[] elementData;

 protected int elementCount;

 protected int capacityIncrement;


 public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
 }


 public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    /**
     * Constructs an empty vector so that its internal data array
     * has size {@code 10} and its standard capacity increment is
     * zero.
     */
    public Vector() {
        this(10);
    }

從上面 Vector 的原始碼中可以看出, Vector 中多了一個構造方法,  Vector(int initialCapacity, int  capacityIncrement). 

capacityIncrement 就是增量因子,如果設定增量因子, 這個 capacityIncrement 會用於對陣列進行擴容.

當呼叫 Vector 無參構造時,  java 預設初始化 initialCapacity 值為 10. 並且設定 capacityIncrement 為0. 

當採用無參構造建立ArrayList 和 Vector 物件時, Vector 和 ArrayList 的預設初始化長度都為10. 只不過 ArrayList 是第一次呼叫 add() 方法時將 elementData 陣列擴容為10, 而 Vector 是初始化時就將 elementData 陣列設定為10.

下面來分析 Vector 的 add() 方法, 看看 Vector 是如何實現對陣列的擴容;

elementCount 是記錄當前陣列元素的個數. 也就是記錄 Vector 集合中元素的個數. 初始化值為0.

下面來看看 ensureCapacityHelper() 方法:

private void ensureCapacityHelper(int minCapacity) {
        // 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;

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

ensureCapacityHelper() 方法首先會判斷 所需容量是否大於當前 elementData陣列的長度,  如果所需容量大於 陣列容量, 則呼叫 grow() 方法對陣列進行擴容. 

通過上面 grow() 方法的程式碼, 可以看到 capacityIncrement 的作用了, 當 capacityIncrement 的值大於0時, 一般也就是也就是我們建立Vector 物件時呼叫有參構造設定了 capacityIncrement 的值, 陣列擴容的長度為 當前陣列長度加上 capacityIncrement.  

當 capacityIncrement 值為0 時(採用預設構造方法), 陣列擴容為當前陣列容量的 2倍.  最後使用 Arrays.copyOf() 方法對陣列進行擴容.  可以看出 ArrayLsit 和 Vector 的擴容機制的不同.