引言 之前的文章我們學習了一個集合類 "ArrayList" ,今天講它的一個兄弟 Vector 。 為什麼說是它兄弟呢?因為從容器的構造來說,Vector 簡直就是 ArrayList 的翻版,也是基於數組的數據結構,不同的是,Vector的每個方法都加了 synchronized 修飾符,是線程 ...
引言
之前的文章我們學習了一個集合類 ArrayList,今天講它的一個兄弟 Vector。
為什麼說是它兄弟呢?因為從容器的構造來說,Vector 簡直就是 ArrayList 的翻版,也是基於數組的數據結構,不同的是,Vector的每個方法都加了 synchronized 修飾符,是線程安全的。
類聲明
用idea打開 Vector 的源碼,不難發現,它的類聲明跟 ArrayList 一模一樣,都是繼承了AbstractList,並且都實現了RandomAccess 介面,遍歷元素用for迴圈的效率要優於迭代器。
* @author Lee Boynton
* @author Jonathan Payne
* @see Collection
* @see LinkedList
* @since JDK1.0
*/
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
值得說明的是,從註釋上來看,Vector 是 JDK1.0版本就引進的,屬於最古老的集合類的那一批,而ArrayList是 1.2才引進的,所以說,Vector才是哥哥,ArrayList是小弟,哈哈~~~~
基本變數和構造函數
基本變數
Vector 的基本變數有四個,分別是:
- 底層數組
protected Object[] elementData;
- 數組元素個數
protected int elementCount;
- 增長的容量大小,如果這個值小於或等於0,擴容時會擴大 2 倍,
capacityIncrement
- 最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
構造函數
//創建初識容量為10的數組,增長量0
public Vector() {
this(10);
}
//創建初識容量可變的數組,增長量為0
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
//創建初識容量可變的數組,可設置增長量
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(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);
}
看的出來,Vector的構造器和成員變數和ArrayList大同小異。
成員方法
擴容
Vector 與 ArrayList 雖然很類似,但在擴容大小這方面還是有區別的,ArrayList 預設擴容後的大小為原容量 的1.5倍,而Vector則是先判斷增長量大小,如果是非正數,那就擴大為原來的2倍,看一下它的擴容方法:
//參數是最小需要的容量
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//如果增長量不大於0,擴容為2倍大小
//一般預設創建的容器都是不傳增長量的,所以預設增長量是0,也就是預設直接擴容兩倍
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
添加
Vector的添加方法都是加上 synchronized
關鍵字的,並且添加前檢測容量,判斷是否擴容:
//加入元素到數組結尾,同步的
public synchronized boolean add(E e) {
modCount++;
//檢測容量
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
//檢測容量大小,超過數組長度就做擴容
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
public void add(int index, E element) {
insertElementAt(element, index);
}
//插入對應索引的元素
public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
ensureCapacityHelper(elementCount + 1);
//插入元素前,把其索引後面的元素統一後移一位
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
elementData[index] = obj;
elementCount++;
}
public synchronized void addElement(E obj) {
modCount++;
//保證容量足夠
ensureCapacityHelper(elementCount + 1);
//直接設置最後一個元素的數據
elementData[elementCount++] = obj;
}
//添加整個集合
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;
}
//在對應的索引處插入一個集合
public synchronized boolean addAll(int index, Collection<? extends E> c) {
modCount++;
if (index < 0 || index > elementCount)
throw new ArrayIndexOutOfBoundsException(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityHelper(elementCount + numNew);
//計算要移動多少個元素
int numMoved = elementCount - index;
if (numMoved > 0)
//把插入位置後面的元素後移這麼多位
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//複製元素數組
System.arraycopy(a, 0, elementData, index, numNew);
elementCount += numNew;
return numNew != 0;
}
Vector的添加方法代碼不是很複雜,跟ArrayList 一樣,本質上都是對數組做插入數據的操作,不同的是,方法都加了synchronized 修飾,所以,它的添加方法都是線程安全的。
其他操作元素的方法也是這樣的套路,這裡不打算一一列舉了,因為都跟ArrayList 差不多,另外,Vector 比 ArrayList 多了一個迭代方法
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");
}
};
}
返回的是一個Enumeration 介面對象,大概也是個容器介面,沒用過,不說太多。
Vector 對比 ArrayList
最後,總結一下 Vector 和 ArrayList 的對比吧。
相同點:
底層都是基於數組的結構,預設容量都是10;
都實現了RandomAccess 介面,支持隨機訪問;
都有擴容機制;
區別:
Vector 的方法有做同步操作,是屬於線程安全的,而ArrayList 是非線程安全的;
Vector預設情況下擴容後的大小為原來的2倍,而ArrayList 是1.5倍;
Vector 比 ArrayList 多了一種迭代器 Enumeration;
雖然Vector相較ArrayList做了同步的處理,但這樣也影響了效率,因為每次調用方法都要獲取鎖,所以,一般情況下,對集合的線程安全沒有需求的話,推薦使用 ArrayList。