Java集合 Vector的底层详解

Java集合的 Vector底层讲解

Vector作为List的另外一个典型的实现类,完全支持List的全部功能,Vector的实现其实和ArrayList的底层实现很类似,都是封装了一个Object[],但Vector是一个比较古老的集合,JDK1.0就已经存在,建议不要使用这个集合,Vector与ArrayList的主要区别是:Vector是线程安全的,ArrayList是非线程安全的,但性能上Vector比ArrayList低。

基本属性

protected Object[] elementData;  //存放元素的数组
protected int elementCount;    //已经放入数组的元素个数
protected int capacityIncrement; //数组的增长系数

源码解析

package java.util;

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

    //定义数组,存放元素
    protected Object[] elementData;

    //已经放入数组的元素数量
    protected int elementCount;

    //增长的系数
    protected int capacityIncrement;

    //可序列化版本号
    private static final long serialVersionUID = -2767605614048989439L;

    //构造方法,提供初始大小,和增长系数
    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);
    }

    //构造方法,将指定的集合元素转化为Vector
    public Vector(Collection<? extends E> c) {
        elementData = c.toArray();
        elementCount = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        //判断c.toArray是否是Object[]类型
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }

    //将elementData中的元素全部拷贝到anArray数组中
    public synchronized void copyInto(Object[] anArray) {
        System.arraycopy(elementData, 0, anArray, 0, elementCount);
    }

    //将数组长度设置为等于vector的个数
    public synchronized void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (elementCount < oldCapacity) {
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }

    //扩充容量
    public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }

    //扩充容量帮助函数
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    //最大容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    //扩充容量执行方法
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //根据capacityIncrement进行判断,capacityIncrement> 0 增加capacityIncrement个容量,否则容量扩充当前容量的一倍
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //扩容操作,生成已给新的数组,容量为newCapacity,并将elementData中的元素全部拷贝到新数组中,并将新生成的数组在赋值给elementData 
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
  }

总结
Vector和ArrayList的底层实现方式非常的相近,官方说少使用Vector,还是尽量少使用,通过源码可以看出,每个方法都添加了synchronized关键字来保证同步,所以它是线程安全的,但是正是这些方法的同步,让其效率大大的降低了。比ArrayList的效率要慢

因此,给出以下几点总结:
1、Vector有四个不同的构造函数。 无参构造的容量默认值为10
2、扩充容量的方法ensureCapacityHelper。与ArrayList不同的是,Vector在每次增加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量。当容量不足以容纳当前的元素个数时,就看构造方法中传入的容量增长系数CapacityIncrement是否为0,如果不为0,就设置新的容量为 旧容量 + 容量增长量;如果为0,设置新的容量为旧的容量的2倍,如果设置后的容量还不够,则直接新的容量设置为 旧容量 + 传入参数所需要的容量 而后同样用Arrays.copyof()方法将元素拷贝到新的数组。
3、很多方法都加入了synchronized同步语句,来确保线程安全。
4、Vector在查找给定元素索引值等方法中,源码都将该元素的值分为null和不为null两种情况处理,Vector中允许元素为null
5、其他很多地方与ArrayList实现大同小异,Vector现在已经不再使用。

### JavaVector底层实现原理 #### 一、Vector的数据结构 `Vector` 是 Java 中的一个动态数组,其底层是基于数组实现的。这意味着 `Vector` 的内部存储是一个连续的内存空间,用于保存元素[^1]。 当创建一个 `Vector` 对象时,默认情况下它会分配一块固定大小的数组作为初始容量。如果需要更多的存储空间,则通过扩容机制自动调整数组的大小。以下是几种常见的构造方法及其作用: - **无参构造函数**:`public Vector()` 创建一个默认初始容量为 10 的向量。 - **指定初始容量**:`public Vector(int initialCapacity)` 创建具有给定初始容量的向量。 - **带增量参数的构造函数**:`public Vector(int initialCapacity, int capacityIncrement)` 创建具有给定初始容量以及每次扩容增长数量的向量。 - **从集合初始化**:`public Vector(Collection<? extends E> c)` 使用现有集合的内容初始化一个新的向量[^3]。 #### 二、Vector的核心操作——添加元素 在 `Vector` 中调用 `add(E e)` 方法时,首先检查当前数组是否有足够的剩余空间容纳新元素。如果没有足够空间,则触发扩容逻辑。具体过程如下: 1. 判断当前数组长度是否满足需求; 2. 如果不满足,则计算新的数组大小并创建更大的数组; 3. 将旧数组中的所有元素复制到新数组中; 4. 把新增加的元素放入最后的位置上完成插入动作[^4]。 值得注意的是,在多线程环境下,由于所有的修改操作都被标记为了同步 (`synchronized`) ,因此即使多个线程同时尝试改变同一个 `Vector` 实例也不会引发并发问题。然而这种设计也带来了性能上的开销,使得它的运行速度通常慢于非线程安全版本如 `ArrayList`。 #### 三、扩容机制详解 每当发生溢出情况即超出当前可用索引范围的时候就会启动扩展流程。对于 `Vector` 而言,默认情况下每次都会将其容量翻倍;而如果你指定了 `capacityIncrement` 参数的话,则按照该值逐步增加额外的空间直到能够放下全部所需项为止。 例如,假设有一个初始容量为 5 并设置了每步增益单位为 3 的实例 A 。那么第一次满载之后下一次能承载的最大数目将是原来的两倍再加三个位置也就是总共十三个槽位可供利用。 ```java // 示例代码展示如何设置不同的构造方式影响最终表现形式 import java.util.Vector; public class Main { public static void main(String[] args){ // 构造一个带有自定义初始容量和增量策略的对象B Vector<Integer> B=new Vector<>(8 ,7); System.out.println("Initial Capacity:"+B.capacity()); for (int i=0;i<20;i++) { B.add(i); if ((i+1)%9==0){ System.out.printf("%d elements added.New size:%d New capcity:%d%n",i+1,B.size(),B.capacity());} } } } ``` 上述程序片段展示了随着不断追加数值进入容器当中所经历的变化规律。每一次达到临界点后便会依据既定规则重新规划整体布局从而适应更多待处理项目的需求。 --- ### 总结 综上所述,`Vector` 结合了传统静态数组高效随机存取的优点同时也克服了它们难以灵活应对未知规模输入集这一缺陷。尽管如此,考虑到现代应用环境中绝大多数场景并不涉及严格意义上的跨进程共享资源竞争状况因而更倾向于选用轻量化替代品比如 `ArrayList` 来获取更高的执行效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值