(2)常用的集合类之Vector

本文详细解析了Vector类,一种线程安全的动态数组实现。探讨了其内部结构、扩容机制、线程安全性和快速失败机制,以及如何正确使用Vector避免潜在的线程安全问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.简介(有参考)

vector是一个矢量队列,继承自AbstractList,实现了List,RandomAccess,Cloneable,java.io.Serializable等接口。

vector继承AbstractList,实现了List,所以,它是一个队列,实现了增加、删除、修改、遍历等功能。

vector实现了RandomAccess,可以进行随机访问。

vector实现了Cloneable,重载了其中的clone()方法,可以进行克隆。

vector实现了Serializable,可进行序列化。

vector是线程安全的(后面会讲到)


2.重要成员变量及构造函数

protected Object[] elementData;  //数组缓冲区,存储矢量的组件即数据

protected int elementCount; //数组的大小

protected int capacityIncrement; //容量增长度,自动增长,如果增长度很慢趋近于零,则会成倍增长。

public Vector() { //默认大小为10

    this(10);

}

public Vector(int initialCapacity) {

    this(initialCapacity, 0);  //默认容量增长度为0

}

public Vector(int initialCapacity, int capacityIncrement) {....} // 执行真正的初始化

 

public Vector(Collection<? extends E> c) { //集合为参,初始化

    elementData = c.toArray();

    elementCount = elementData.length;

    // c.toArray might (incorrectly) not return Object[] (see 6260652)

    //Arrays的toArray()方法不一定会返回Object[].class;

    /**        与传进来的collection有关,如:

     *         List<Object> aa = Arrays.asList("a",1,'c',0.2f);elementData.getClass() 为object[]

     *         List<String> dd = Arrays.asList("a","bb");elementData.getClass() 为string[]

     *         因为定义的elementData 就是为object[],不然会报错

     * */

    if (elementData.getClass() != Object[].class)

        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);

}


3.常用方法

public synchronized boolean add(E e) {

    modCount++;    //修改次数自增

    ensureCapacityHelper(elementCount + 1); //确保容量足够

    elementData[elementCount++] = e;  //新增的空位置添加新元素

    return true;

}

private void ensureCapacityHelper(int minCapacity) {

    if (minCapacity - elementData.length > 0)

        grow(minCapacity);  //执行扩容方法

}

private void grow(int minCapacity) {

    //当前vector的长度

    int oldCapacity = elementData.length;

    //新的容量-当前的+(增长度设置了且大于零则直接使用,否则设置的增长度为当前长度,即每次扩大一倍)

    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);

    //扩容一倍或扩容后(n倍)不够,以需要的容量为新的容量

    if (newCapacity - minCapacity < 0)

        newCapacity = minCapacity;

    if (newCapacity - MAX_ARRAY_SIZE > 0)

        newCapacity = hugeCapacity(minCapacity);

    elementData = Arrays.copyOf(elementData, newCapacity); //底层还是System.arraycopy方法,将源数组扩展了一个空位置(add方法最后执行添加)

}

 

set\get 方法实现

E elementData(int index) {

    return (E) elementData[index];

}

remove等方法与ArrayList差不多,不再赘述

遍历:

Iterator it = vector.iterator();  //迭代器遍历

while (it.hasNext()){

    Object obj = it.next();

    System.out.println(obj);

}

for (int i = 0; i < vector.size(); i++) { //随机访问

    System.out.println(vector.get(i));

}

for (Object obj : vector) {     //常见foreach

    System.out.println(obj);

}

Object obj = null;   //枚举遍历

Enumeration eums = vector.elements();   

while (eums.hasMoreElements()){

    obj = eums.nextElement();

    System.out.println(obj);

}

--1.8新特性遍历集合lambda表达式

1.vector.forEach(value -> System.out.println(value));

2.vector.forEach(new Consumer<Object>() {

    @Override

    public void accept(Object value) {

        if (vector.size() >0){

            System.out.println(value);

        }

    }

});

3.vector.forEach(value -> {

    if (vector.size() >0){

        System.out.println(value);

    }

});

--clone、remove、toarray等很多方法,底层都是关于数组的copy、增删相关操作。


4.扩容机制

private void grow(int minCapacity) {

    //当前vector的长度

    int oldCapacity = elementData.length;

    //新的容量-当前的长度+(增长度设置了且大于零则直接使用即扩大capacityIncrement,否则设置的增长度为当前长度即每次扩大一倍

    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);

    //扩容一倍或扩容后(n倍)不够,以需要的容量为新的容量

    if (newCapacity - minCapacity < 0)

        newCapacity = minCapacity;

    if (newCapacity - MAX_ARRAY_SIZE > 0)

        newCapacity = hugeCapacity(minCapacity);

    elementData = Arrays.copyOf(elementData, newCapacity); //底层还是System.arraycopy方法,将源数组扩展了一个空位置(add方法最后执行添加)

}


5.快速失败机制

同ArrayList的快速失败机制--如在迭代器里面做add、remove操作。 因为调用iterator的next()方法 会判断modCount(修改次数)。


6.线程安全方面

问:对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全?

答:同步容器中的所有自带方法都是线程安全的,因为方法都使用synchronized关键字标注。但是,对这些集合类的复合操作无法保证其线程安全性。需要客户端通过主动加锁来保证。

由于我们自己已知Vector等同步容器是线程安全的,所以我们通常在多线程场景中会直接拿来使用,并不会考虑太多,从而可能导致问题。

所以,我们在使用同步容器的时候,如果只使用其中的自带方法,那么可以放心使用,因为他们是线程安全的,但是如果我们想做复合操作,尤其是涉及到删除容器中的元素时,一定要注意是否需要客户端主动加锁。

下面,我们考虑以下代码,如果在多线程场景中使用会不会出现线程安全问题:(如一个线程先删除了大小为5的数组的最高位的数据,另一个再get最高位,则会报错)

for (int i = 0; i < v.size(); i++) {

    System.out.println(v.get(i));

}

显然,以上代码在迭代的过程中,并不会出现线程安全问题。但是,如果在程序中还有以下代码有可能被同时调用呢?

for (int i = 0; i < v.size(); i++) {

    v.remove(i);

}

由于,不同线程在同一时间操作同一个Vector,其中包括删除操作,那么就同样有可能发生线程安全问题。所以,在使用同步容器的时候,如果涉及到多个线程同时执行删除操作,就要考虑下是否需要加锁。

synchronized (vector) {for(...)} 加锁

参考链接:http://www.importnew.com/26359.html


7.总结    

    vector实际上和ArrayList的功能大体相似,但是它基本所有的方法都加了Synchronized关键字,即同步安全的。 但就是因为加了Synchronized,当达到一定数据量时,在性能方面是不如ArrayList的,而且需注意的就是--vector在多线程情况下,也并不安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值