首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Vector 深度解析:同步動態數組源碼、擴容策略與遍歷效率實測

     編輯:Java 相關知識

java.util.Vector 是 JDK 1.0 時代的同步動態數組,雖已被 ArrayList + 併發包取代,但在大量遺留系統、教學代碼中仍廣泛存在。本文從源碼級剖析其同步機制、擴容策略、Enumeration 遍歷特性,並給出遍歷效率實測數據。

一、類定位與核心特性

public class Vector<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, Serializable { }
  • 繼承 AbstractList,實現 List、RandomAccess(支持快速隨機訪問)、Cloneable、Serializable。
  • 所有公共方法均加 synchronized → 線程安全,但鎖粒度粗、爭用時性能瓶頸明顯。
  • 底層 protected Object[] elementData + int elementCount 實現動態數組。
  • 支持 Enumeration 遍歷(遺留特性),現代代碼建議用 Iterator/for-each。

二、四種構造函數與擴容策略

構造函數說明
Vector()默認容量 10,擴容翻倍
Vector(int initialCapacity)指定初始容量,擴容翻倍
Vector(int initialCapacity, int capacityIncrement)指定初始容量與固定增量(>0 時每次擴容 +increment)
Vector(Collection<? extends E> c)複製構造,容量 = 集合大小

擴容核心邏輯 ensureCapacityHelper

private void ensureCapacityHelper(int minCapacity) {
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
        Object[] oldData = elementData;
        int newCapacity = (capacityIncrement > 0)
            ? (oldCapacity + capacityIncrement)   // 固定增量模式
            : (oldCapacity * 2);                  // 默認翻倍模式
        if (newCapacity < minCapacity) newCapacity = minCapacity;
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

對比 ArrayList:ArrayList 固定 1.5 倍 + 1((old*3)/2+1),Vector 可配置固定增量或翻倍,靈活但擴容頻率可能更高。

三、核心源碼邏輯精選

3.1 同步方法模式

public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

public synchronized E get(int index) {
    if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index);
    return (E) elementData[index];
}

所有修改(add/remove/set/insert)與讀取(get/size/isEmpty)均同步 → 甚至單線程下也承擔鎖開銷。

3.2 插入/刪除:數組搬移

// insertElementAt(index, obj)
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
elementData[index] = obj;
elementCount++;

// removeElementAt(index)
int j = elementCount - index - 1;
if (j > 0) System.arraycopy(elementData, index + 1, elementData, index, j);
elementCount--;
elementData[elementCount] = null;  // 釋放引用助 GC

3.3 Enumeration 實現(遺留特性)

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 (E) elementData[count++];
            }
            throw new NoSuchElementException("Vector Enumeration");
        }
    };
}

四、四種遍歷方式效率實測(10 萬元素,JDK 8)

// 測試代碼片段
iteratorThroughRandomAccess:6 ms   // for (int i=0; i
結論:實現 RandomAccess 的 Vector,下標隨機訪問最快,Enumerator 次之,迭代器最慢。實際開發首選 for (int i=0; i。

五、Vector vs ArrayList 核心差異總結

維度VectorArrayList
線程安全方法級 synchronized非線程安全
序列化未實現 Serializable實現 Serializable
擴容策略可配增量 或 2倍固定 1.5倍+1
構造函數4 個3 個
Enumeration支持不支持
性能(單線程)較低(鎖開銷)極高

六、實戰示例

import java.util.*;

public class VectorDemo {
    public static void main(String[] args) {
        Vector<String> vec = new Vector<>();
        vec.add("1"); vec.add("2"); vec.add("3"); vec.add("4"); vec.add("5");

        // 修改與插入
        vec.set(0, "100");
        vec.add(2, "300");  // 索引 2 插入
        System.out.println("vec: " + vec);  // [100, 2, 300, 3, 4, 5]

        // 查找
        System.out.println("indexOf(100): " + vec.indexOf("100"));      // 0
        System.out.println("lastIndexOf(100): " + vec.lastIndexOf("100")); // 0

        // 首尾元素
        System.out.println("first: " + vec.firstElement());  // 100
        System.out.println("last: " + vec.lastElement());    // 5
        System.out.println("elementAt(2): " + vec.elementAt(2)); // 300

        // 容量與大小
        System.out.println("size: " + vec.size() + ", capacity: " + vec.capacity());

        // 子列表
        System.out.println("subList(1,4): " + vec.subList(1, 4)); // [2, 300, 3]

        // Enumeration 遍歷
        System.out.println("\nEnumeration 遍歷:");
        for (Enumeration<String> enu = vec.elements(); enu.hasMoreElements(); )
            System.out.println(enu.nextElement());

        // retainAll 保留交集
        Vector<String> retain = new Vector<>();
        retain.add("100"); retain.add("300");
        vec.retainAll(retain);
        System.out.println("\nretainAll 後: " + vec); // [100, 300]

        // 轉數組
        String[] arr = vec.toArray(new String[0]);
        for (String s : arr) System.out.println("arr: " + s);

        // 清空
        vec.clear();
        System.out.println("isEmpty: " + vec.isEmpty());
    }
}

七、現代替代方案指南

  1. 單線程/線程隔離 → ArrayList(性能最優)。
  2. 多線程讀多寫少 → CopyOnWriteArrayList(寫時復制,遍歷無鎖)。
  3. 多線程讀寫均衡/寫多 → Collections.synchronizedList(new ArrayList()) 或 手動加鎖 ArrayList。
  4. 高併發隊列/棧 → ConcurrentLinkedQueue、ArrayBlockingQueue、ConcurrentLinkedDeque。
  5. 遺留代碼 → 保留 Vector 但理解其同步瓶頸,逐步遷移。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved