【Java源碼分析】Vector源碼分析

類的聲明

public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{}

仔細對比ArrayList的類的定義就可以看出,Vector實現的接口以及父類和ArrayList是一樣的。實際上從繼承體系上也可以看出兩者很類似,同屬於List的實現類。

  1. Vector是一個實現了自增長的數組的對象集合,由於底層實現是數組,所以支持下標訪問。同ArrayList一樣,Vector的大小也是支持增長grow和縮小shrink的
  2. Vector對象爲了優化存儲結構通常會維護一個capacity變量和一個capacityIncrement變量。capacity是和容量大小略大的值,但是Vector增長的時候並不是按ArrayList那種增加爲原來的1.5倍,而是增加capacityIncrement大小。這種方式可以在知道需要多少存儲空間來存儲將要添加的對象的時候,一次性申請足夠的存儲空間,避免頻繁的增加Vector的大小
  3. 指向Vector的迭代器同樣會因爲遍歷的時候修改Vector而導致ConcurrentModification異常而出現fail-fast現象
  4. Vector並不是一開始就存在於List,而是後來1.2之後添加的。Vector和其他List的最大的不同點在於其線程安全性,正是因爲實現了線程安全性,導致在單線程下性能比不上ArrayList,所以如果並不在多線程環境下使用,還是建議使用ArrayList

    protected Object[] elementData; // 存儲數據的數組
    protected int elementCount; // 集合中的對象個數
    protected int capacityIncrement; // 增長尺度

構造函數

// 1
public Vector() {
    this(10);
}

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

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

// 4
public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

四個構造函數,很明顯無參構造的時候默認是構造一個初始容量爲10,增長尺度爲0的空集合,構造函數2和3一樣根據指定的初始容量和增長尺度構造空集合,默認增長尺度都是0.第四個構造函數根據給定集合中的數據初始化一個新的Vector

存儲空間收縮

public synchronized void trimToSize() {
    modCount++;
    int oldCapacity = elementData.length;
    if (elementCount < oldCapacity) {
        elementData = Arrays.copyOf(elementData, elementCount);
    }
}

將實際的容量capacity調整爲實際存儲的數據個數。這裏之所以需要拷貝一下,是爲了將就的大存儲空間釋放,開闢新的較小的存儲空間來存儲剩餘對象。此外,可以看到由於線程安全性,該方法使用了同步關鍵字

擴容

public synchronized void ensureCapacity(int minCapacity) {
    if (minCapacity > 0) {
        modCount++;
        ensureCapacityHelper(minCapacity);
    }
}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

// ensureCapacityHelper()最終調用了grow()方法
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);
}

新擴展的大小爲舊容量加上capacityIncrement。如果capacityIncrement小於等於0,那麼新的容量將會是原來舊容量的兩倍這一點可以從代碼上看出來。注意grow()方法沒有做線程同步,但是它實際上是被內部的線程同步函數調用的,所以不會發生不一致的問題。

設置大小

public synchronized void setSize(int newSize) {
    modCount++;
    if (newSize > elementCount) {
        ensureCapacityHelper(newSize);
    } else {
        for (int i = newSize ; i < elementCount ; i++) {
            elementData[i] = null;
        }
    }
    elementCount = newSize;
}

在設置大小的過程中存在兩種情況,一種是新的大小比原來的大,那麼多於的空位置會置爲NULL;另一種情況是新的大小比原來的小,那麼下標比newSize大的元素都被丟棄

將Vector中對象轉換爲枚舉

public Enumeration<E> elements() {
    return new Enumeration<E>() {
        int count = 0;

        public boolean hasMoreElements() {
            return count < elementCount;
        }

        public E nextElement() {
            synchronized (Vector.this) {
                if (count < elementCount) {
                    return elementData(count++);
                }
            }
            throw new NoSuchElementException("Vector Enumeration");
        }
    };
}

增刪方法,這些實現和ArrayList類似,只是增加了Synchrnized關鍵字進行多線程的同步,例如刪除所有元素

public synchronized void removeAllElements() {
    modCount++;
    // Let gc do its work
    for (int i = 0; i < elementCount; i++)
        elementData[i] = null;

    elementCount = 0;
}

該方法將Vector中的對象全部刪除,並且將對象個數置爲0

添加

public synchronized boolean addAll(Collection<? extends E> c) {
    modCount++;
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityHelper(elementCount + numNew);
    System.arraycopy(a, 0, elementData, elementCount, numNew);
    elementCount += numNew;
    return numNew != 0;
}

將c中的所有數據添加到Vector 的尾部。存在一種異常情況就是參數c就是this,此時程序的行爲使不確定的

刪除和保留指定集合中的元素

public synchronized boolean retainAll(Collection<?> c) {
    return super.retainAll(c);
}

public synchronized boolean removeAll(Collection<?> c) {
    return super.removeAll(c);
}

前者保留同時位於Vector中和c中的數據,其他數據刪除;後者是刪除既在Vector中又在c中的數據

查找指定對象的下標

public synchronized int indexOf(Object o, int index) {
    if (o == null) {
        for (int i = index ; i < elementCount ; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = index ; i < elementCount ; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

該方法的第二個參數index說明實際的查找起點是從index開始,默認爲0。從該函數也可以看出Vector中也是允許NULL的存在的

轉換爲Array

public synchronized Object[] toArray() {
    return Arrays.copyOf(elementData, elementCount);
}

@SuppressWarnings("unchecked")
public synchronized <T> T[] toArray(T[] a) {
    if (a.length < elementCount)
        return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());

    System.arraycopy(elementData, 0, a, 0, elementCount);

    if (a.length > elementCount)
        a[elementCount] = null;

    return a;
}

第二個泛型toAyyay和之前的也是一樣的,在a.length < elementCount也就是存儲空間不足的時候,會新建一個新的存儲空間然後拷貝到Array中,否則,直接拷貝到a中,a中剩餘部分直接置爲NULL

相等性判斷

public synchronized boolean equals(Object o) {
    return super.equals(o);
}

這個方法之前是沒有的,相等的條件是比較嚴格的,還有當o也是一個List並且他們的size 想的,元素相等,並且元素的順序是一樣的。也就是對應位置的元素是相等的,此時才返回true

返回一個子List

public synchronized List<E> subList(int fromIndex, int toIndex) {
    return Collections.synchronizedList(super.subList(fromIndex, toIndex),
                                        this);
}

返回的子List支持所有List的操作。主要用於區間操作的時候返回一個子區間的數據,類似於數據庫中的表和視圖的關係,正式因爲如此,對於所返回的subList的操作最終會反映到Vector中,相應的對Vector的數據操作也會反映到subList中。例如list.subList(from, to).clear();操作改變的是實際的Vector.但是如果對Vector的操作是增刪等改變結構的操作,那麼所返回的這個subList就失效了

序列化

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
    final java.io.ObjectOutputStream.PutField fields = s.putFields();
    final Object[] data;
    synchronized (this) {
        fields.put("capacityIncrement", capacityIncrement);
        fields.put("elementCount", elementCount);
        data = elementData.clone();
    }
    fields.put("elementData", data);
    s.writeFields();
}

將Vector中的數據序列化到流中,注意該方法是私有方法

Java中實際使用Vector遠遠沒有C++中使用的普遍,可能是平時寫多線程的代碼不多,或者Vector本身替代性太強了。

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