Java容器——Vector(Java8)源碼解析

    Vector是Java早期實現的容器,自JDK1.0就存在。目前在日常使用中逐漸被ArrayList或同步的ConcurrentLinkedQueue等代替,不過在早期的代碼中和類庫中,仍經常能見到Vector,因此有必要對其的組成和原理進行基本的瞭解。

    

   Vector的繼承關係如上圖所示,可以看到,Vector和ArrayList的繼承關係完全一致(可參考筆者先前的文章點擊打開鏈接)。那爲何有了ArrayList還要構造出一個Vector呢?那下面從源碼角度來了解一下Vector。

    一 組成元素

/**
 *
 * 存儲元素的數組
 *
 * @serial
 */
protected Object[] elementData;

/**
 *
 * 元素個數
 */
protected int elementCount;

/**
 * 擴容數量
 * 
 */
protected int capacityIncrement; 

    這幾個變量從字面意思都比較容易理解,其中最後一個capacityIncrement是當vector容量不夠了,需要一次性進行擴容的數量。需要說明的是,同ArrayList一樣,capacity(也就是elementData.length)和elementCount是兩個值,一個顯示了當前vector能承載多少元素,一個是已經存放的元素。

    二 關鍵函數

   1 構造函數

    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);
    }

  
    public Vector() {
        this(10);
    }

    public Vector(Collection<? extends E> c) {
        elementData = c.toArray();
        elementCount = elementData.length;
        // defend against c.toArray (incorrectly) not returning Object[]
        // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }

    構造函數都比較簡單明瞭,圍繞着initialCapacity和capacityIncrement展開,設置了初始化長度和每次增長的長度。

    2 增刪改查

 public synchronized void insertElementAt(E obj, int index) {
        if (index > elementCount) {
            throw new ArrayIndexOutOfBoundsException(index
                                                     + " > " + elementCount);
        }
        modCount++;
        final int s = elementCount;
        Object[] elementData = this.elementData;
        if (s == elementData.length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = obj;
        elementCount = s + 1;
    }

    插入元素前,首先判斷下標和擴容,然後將舊數組拷貝到新創建的數組中,實現過程比較清晰。需要注意的是,插入元素使用了synchronized關鍵字,即這個操作是加鎖的操作,而且是對整個vector操作加鎖,這就阻塞了對該vector的使用。   

public synchronized void removeElementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        int j = elementCount - index - 1;
        if (j > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        modCount++;
        elementCount--;
        elementData[elementCount] = null; /* to let gc do its work */
    }

 

public synchronized E set(int index, E element) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }   

    刪除操作是將指定刪除位置以後的元素依次前移一位,設置元素是將指定位置的元素用給定元素代替,也都是加鎖的操作。

 public synchronized E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        return elementData(index);
    }

    如果說前面的增刪改操作涉及到對vector的修改,加鎖爲了保證線程安全性可以理解。而獲取元素這個對vector來說並不改變其本身同時也是最體現List性能的方法上,加鎖就只能是拖累性能了。

小結

   vector由於其功能和實現與ArrayList基本一致,不過對重要操作都使用了加鎖導致其性能有較大損失,在實際使用過程中使用並不太多。將其get功能去鎖的有CopyOnWriteArrayList,既不影響其線程安全性,又有效提升隨機訪問速度。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章