在java提高篇(二一)—–ArrayList、java提高篇(二二)—LinkedList,詳細講解了ArrayList、linkedList的原理和實現過程,對於List接口這里還介紹一個它的實現類Vector,Vector 類可以實現可增長的對象數組。
一、Vector簡介
Vector可以實現可增長的對象數組。與數組一樣,它包含可以使用整數索引進行訪問的組件。不過,Vector的大小是可以增加或者減小的,以便適應創建Vector后進行添加或者刪除操作。
Vector實現List接口,繼承AbstractList類,所以我們可以將其看做隊列,支持相關的添加、刪除、修改、遍歷等功能。
Vector實現RandmoAccess接口,即提供了隨機訪問功能,提供提供快速訪問功能。在Vector我們可以直接訪問元素。
Vector 實現了Cloneable接口,支持clone()方法,可以被克隆。
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
Vector提供了四個構造函數:
/** * 構造一個空向量,使其內部數據數組的大小為 10,其標准容量增量為零。 */ public Vector() { this(10); }</span><span style="color: #008000">/**</span><span style="color: #008000"> * 構造一個包含指定 collection 中的元素的向量,這些元素按其 collection 的迭代器返回元素的順序排列。 </span><span style="color: #008000">*/</span> <span style="color: #0000ff">public</span> Vector(Collection<? <span style="color: #0000ff">extends</span> E><span style="color: #000000"> c) { elementData </span>=<span style="color: #000000"> c.toArray(); elementCount </span>=<span style="color: #000000"> elementData.length; </span><span style="color: #008000">//</span><span style="color: #008000"> c.toArray might (incorrectly) not return Object[] (see 6260652)</span> <span style="color: #0000ff">if</span> (elementData.getClass() != Object[].<span style="color: #0000ff">class</span><span style="color: #000000">) elementData </span>=<span style="color: #000000"> Arrays.copyOf(elementData, elementCount, Object[].</span><span style="color: #0000ff">class</span><span style="color: #000000">); } </span><span style="color: #008000">/**</span><span style="color: #008000"> * 使用指定的初始容量和等於零的容量增量構造一個空向量。 </span><span style="color: #008000">*/</span> <span style="color: #0000ff">public</span> Vector(<span style="color: #0000ff">int</span><span style="color: #000000"> initialCapacity) { </span><span style="color: #0000ff">this</span>(initialCapacity, 0<span style="color: #000000">); } </span><span style="color: #008000">/**</span><span style="color: #008000"> * 使用指定的初始容量和容量增量構造一個空的向量。 </span><span style="color: #008000">*/</span> <span style="color: #0000ff">public</span> Vector(<span style="color: #0000ff">int</span> initialCapacity, <span style="color: #0000ff">int</span><span style="color: #000000"> capacityIncrement) { </span><span style="color: #0000ff">super</span><span style="color: #000000">(); </span><span style="color: #0000ff">if</span> (initialCapacity < 0<span style="color: #000000">) </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> IllegalArgumentException("Illegal Capacity: "+<span style="color: #000000"> initialCapacity); </span><span style="color: #0000ff">this</span>.elementData = <span style="color: #0000ff">new</span><span style="color: #000000"> Object[initialCapacity]; </span><span style="color: #0000ff">this</span>.capacityIncrement =<span style="color: #000000"> capacityIncrement; }</span></pre>
在成員變量方面,Vector提供了elementData , elementCount, capacityIncrement三個成員變量。其中
elementData :"Object[]類型的數組",它保存了Vector中的元素。按照Vector的設計elementData為一個動態數組,可以隨着元素的增加而動態的增長,其具體的增加方式后面提到(ensureCapacity方法)。如果在初始化Vector時沒有指定容器大小,則使用默認大小為10.
elementCount:Vector
對象中的有效組件數。
capacityIncrement:向量的大小大於其容量時,容量自動增加的量。如果在創建Vector時,指定了capacityIncrement的大小;則,每次當Vector中動態數組容量增加時>,增加的大小都是capacityIncrement。如果容量的增量小於等於零,則每次需要增大容量時,向量的容量將增大一倍。
同時Vector是線程安全的!
二、源碼解析
對於源碼的解析,LZ在這里只就增加(add)刪除(remove)兩個方法進行講解。
2.1增加:add(E e)
add(E e):將指定元素添加到此向量的末尾。
public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); //確認容器大小,如果操作容量則擴容操作 elementData[elementCount++] = e; //將e元素添加至末尾 return true; }
這個方法相對而言比較簡單,具體過程就是先確認容器的大小,看是否需要進行擴容操作,然后將E元素添加到此向量的末尾。
private void ensureCapacityHelper(int minCapacity) { //如果 if (minCapacity - elementData.length > 0) grow(minCapacity); }</span><span style="color: #008000">/**</span><span style="color: #008000"> * 進行擴容操作 * 如果此向量的當前容量小於minCapacity,則通過將其內部數組替換為一個較大的數組倆增加其容量。 * 新數據數組的大小姜維原來的大小 + capacityIncrement, * 除非 capacityIncrement 的值小於等於零,在后一種情況下,新的容量將為原來容量的兩倍,不過,如果此大小仍然小於 minCapacity,則新容量將為 minCapacity。 </span><span style="color: #008000">*/</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> grow(<span style="color: #0000ff">int</span><span style="color: #000000"> minCapacity) { </span><span style="color: #0000ff">int</span> oldCapacity = elementData.length; <span style="color: #008000">//</span><span style="color: #008000">當前容器大小</span> <span style="color: #008000">/*</span><span style="color: #008000"> * 新容器大小 * 若容量增量系數(capacityIncrement) > 0,則將容器大小增加到capacityIncrement * 否則將容量增加一倍 </span><span style="color: #008000">*/</span> <span style="color: #0000ff">int</span> newCapacity = oldCapacity + ((capacityIncrement > 0) ?<span style="color: #000000"> capacityIncrement : oldCapacity); </span><span style="color: #0000ff">if</span> (newCapacity - minCapacity < 0<span style="color: #000000">) newCapacity </span>=<span style="color: #000000"> minCapacity; </span><span style="color: #0000ff">if</span> (newCapacity - MAX_ARRAY_SIZE > 0<span style="color: #000000">) newCapacity </span>=<span style="color: #000000"> hugeCapacity(minCapacity); elementData </span>=<span style="color: #000000"> Arrays.copyOf(elementData, newCapacity); } </span><span style="color: #008000">/**</span><span style="color: #008000"> * 判斷是否超出最大范圍 * MAX_ARRAY_SIZE:private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; </span><span style="color: #008000">*/</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">int</span> hugeCapacity(<span style="color: #0000ff">int</span><span style="color: #000000"> minCapacity) { </span><span style="color: #0000ff">if</span> (minCapacity < 0<span style="color: #000000">) </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span><span style="color: #000000"> OutOfMemoryError(); </span><span style="color: #0000ff">return</span> (minCapacity > MAX_ARRAY_SIZE) ?<span style="color: #000000"> Integer.MAX_VALUE : MAX_ARRAY_SIZE; }</span></pre>
對於Vector整個的擴容過程,就是根據capacityIncrement確認擴容大小的,若capacityIncrement <= 0 則擴大一倍,否則擴大至capacityIncrement 。當然這個容量的最大范圍為Integer.MAX_VALUE即,2^32 - 1,所以Vector並不是可以無限擴充的。
2.2、remove(Object o)
/** * 從Vector容器中移除指定元素E */ public boolean remove(Object o) { return removeElement(o); }</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">synchronized</span> <span style="color: #0000ff">boolean</span><span style="color: #000000"> removeElement(Object obj) { modCount</span>++<span style="color: #000000">; </span><span style="color: #0000ff">int</span> i = indexOf(obj); <span style="color: #008000">//</span><span style="color: #008000">計算obj在Vector容器中位置</span> <span style="color: #0000ff">if</span> (i >= 0<span style="color: #000000">) { removeElementAt(i); </span><span style="color: #008000">//</span><span style="color: #008000">移除</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span><span style="color: #000000">; } </span><span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span><span style="color: #000000">; } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">synchronized</span> <span style="color: #0000ff">void</span> removeElementAt(<span style="color: #0000ff">int</span><span style="color: #000000"> index) { modCount</span>++; <span style="color: #008000">//</span><span style="color: #008000">修改次數+1</span> <span style="color: #0000ff">if</span> (index >= elementCount) { <span style="color: #008000">//</span><span style="color: #008000">刪除位置大於容器有效大小</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> ArrayIndexOutOfBoundsException(index + " >= " +<span style="color: #000000"> elementCount); } </span><span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (index < 0) { <span style="color: #008000">//</span><span style="color: #008000">位置小於 < 0</span> <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span><span style="color: #000000"> ArrayIndexOutOfBoundsException(index); } </span><span style="color: #0000ff">int</span> j = elementCount - index - 1<span style="color: #000000">; </span><span style="color: #0000ff">if</span> (j > 0<span style="color: #000000">) { </span><span style="color: #008000">//</span><span style="color: #008000">從指定源數組中復制一個數組,復制從指定的位置開始,到目標數組的指定位置結束。 </span><span style="color: #008000">//</span><span style="color: #008000">也就是數組元素從j位置往前移</span> System.arraycopy(elementData, index + 1<span style="color: #000000">, elementData, index, j); } elementCount</span>--; <span style="color: #008000">//</span><span style="color: #008000">容器中有效組件個數 - 1</span> elementData[elementCount] = <span style="color: #0000ff">null</span>; <span style="color: #008000">//</span><span style="color: #008000">將向量的末尾位置設置為null</span> }</pre>
因為Vector底層是使用數組實現的,所以它的操作都是對數組進行操作,只不過其是可以隨着元素的增加而動態的改變容量大小,其實現方法是是使用Arrays.copyOf方法將舊數據拷貝到一個新的大容量數組中。Vector的整個內部實現都比較簡單,這里就不在重述了。
三、Vector遍歷
Vector支持4種遍歷方式。
3.1、隨機訪問
因為Vector實現了RandmoAccess接口,可以通過下標來進行隨機訪問。
for(int i = 0 ; i < vec.size() ; i++){ value = vec.get(i); }
3.2、迭代器
Iterator it = vec.iterator(); while(it.hasNext()){ value = it.next(); //do something }
3.2、for循環
for(Integer value:vec){ //do something }
3.4、Enumeration循環
Vector vec = new Vector<>(); Enumeration enu = vec.elements(); while (enu.hasMoreElements()) { value = (Integer)enu.nextElement(); }