Vector源码详解

简介: Vector源码详解

一、介绍

前面我们介绍了java集合中的两种List实现类:基于数组实现的ArrayList和基于双向链表实现的LinkedList,从这两个类的源码中我们注意到,他们的方法实现都是线程不安全的,在多个线程共享一个实例的情况下会出现无法解决的问题。那么我们该如何避免问题的发生以保证线程安全呢?

java为我们提供了一些解决方案:

  • 使用 Collections.synchronizedList(List<T> list)方法,该方法对传入的List对象进行包装,返回一个线程安全的List。保证线程安全的原理就是在我们调用add()remove()等方法时通过使用synchronized代码块对方法进行包装,从而实现线程安全。

    // 线程不安全的List对象
    List<Integer> unSynchronizedList = new ArrayList<>();
    // 线程安全的List对象
    List<Integer> synchronizedList = Collections.synchronizedList(unSynchronizedList);
    
  • 使用CopyOnWriteArrayList,顾名思义,该类采用写入时复制的方法并结合ReentrantLock可重入锁来实现线程安全。

    // 线程安全的List对象
    List<Integer> list = new CopyOnWriteArrayList<>();
    
  • 使用Vector,本篇文章的主角,通过使用synchronized关键字实现线程安全。

    // 线程安全的List对象
    List<Integer> list = new Vector<>();
    

在java的早期版本中,为了解决ArrayList的并发问题,在java1.2中就开始引入了Vector,但是由于synchronized关键字过于重量级且不可控制,容易导致多线程死锁等问题的发生,相当于伤敌一千自损八百,捡了西瓜丢了芝麻。因此从java1.5开始,引入新的保证线程安全的集合实现类CopyOnWriteArrayList

虽然java已经不建议我们使用Vector了,但是由于使用简单,又有哪位同学在并发学习中选择直接绕过它呢?

下面我们看一下Vector的UML图:

继承关系图.png

继承关系图

① 实现了List接口,表示实现了List接口所定义的规范

② 继承自AbstractList抽象类,AbstractList同时也实现了List接口,表示继承了AbstractListList默认实现

① 实现了Cloneable接口,表示具有克隆的功能

② 实现了Serializable接口,表示具有序列化的功能

③ 实现了RandomAccess接口,表示具有随机访问的功能

从UML图中可以看出,Vector与ArrayList的继承关系完全一致。因此我们可以先假设这两个类的功能在使用上也完全一致,但要注意的是Vector是线程安全的,而ArrayList是线程不安全的。

注意:上面提到Vector是为了解决ArrayList线程不安全的问题而引入的,我们可以认为Vector是线程安全的ArrayList,在下面的学习中,我们应当将这两个类的不同点作为学习重点。

关于ArrayList源码的学习,请看往期文章:ArrayList源码

二、成员变量

// 对象数组,具有实际意义,用于保存Vector的元素,由此说明Vector是通过数组保存元素的
protected Object[] elementData;
// elementData中对象的数量
protected int elementCount;
// elementData数组在扩容时的增量
protected int capacityIncrement;


// 继承父类AbstractList的变量
// 在使用迭代器遍历过程中,对结构修改的次数,通过该字段可以实现fail-fast快速失败
protected transient int modCount = 0;

三、构造函数

①指定初始容量和扩容增量

// 该构造函数指定Vector实例的初始容量和扩容时的容量的增量
public Vector(int initialCapacity, int capacityIncrement) {
   
   
    // 调用父类的无参构造空方法,
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = new Object[initialCapacity];
    this.capacityIncrement = capacityIncrement;
}

②指定初始容量

// 指定初始容量,增量为缺省值0。在扩容部分我们可以看到,当增量为0时,实际增量为原始容量,即扩容后的容量为扩容前的2倍
public Vector(int initialCapacity) {
   
   
    this(initialCapacity, 0);
}

③无参构造

// 默认初始容量为10,增量为缺省值0
public Vector() {
   
   
    this(10);
}

④通过一个集合构造

// 该构造函数与ArrayList的构造函数的实现一致
public Vector(Collection<? extends E> c) {
   
   
    Object[] a = c.toArray();
    elementCount = a.length;
    if (c.getClass() == ArrayList.class) {
   
   
        elementData = a;
    } else {
   
   
        elementData = Arrays.copyOf(a, elementCount, Object[].class);
    }
}

四、扩容原理

从Vector的源码来看扩容原理,可以发现它的实现与ArrayList的扩容实现几乎完全一致,唯一不同的地方我把源码贴在下面:

// ArrayList的扩容实现, 扩容后的容量为扩容前容量的1.5倍
private void grow(int minCapacity) {
   
   
    // ...
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // ...
}

// Vector的扩容实现
// 如果在调用构造函数时指定的扩容增量大于0,则扩容后的容量=扩容前容量+扩容增量
// 否则,扩容后的容量=扩容前容量*2
private void grow(int minCapacity) {
   
   
    // ...
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    // ...
}

五、补充说明

Vector从源码上来看,无论是增加元素、删除元素、修改元素、获取元素等方法,与ArrayList大同小异,几乎没有差别,建议读者在学习时以ArrayList作为重点去学习它的源码,然后再以它为参考,对Vector有个基本了解就行了。

再说说面试,Vector的重点知识其实很少很少,一般面试时面试官是不会问的,那么如果问了,可能会找出哪些问题?

①Vector和ArrayList的相同点是什么,不同点是什么,各自的使用场景是什么。

②以Vector线程安全为引子,对synchronized关键字的原理大文特问。

六、Vector和ArrayList的主要对比

相同点 不同点
底层结构 数组
初始容量 10
构造函数 1.都可以指定初始容量构造
2.都可以通过集合构造
1.ArrayList有三个,Vector有四个
2.ArrayList可以通过集合、初始容量构造;Vector可以通过集合、初始容量、扩容增量构造
扩容 ArrayList扩容后的容量为扩容前容量的1.5倍
Vector扩容后的容量为 扩容前容量+扩容增量扩容前容量*2
相关文章
|
容器
库中如何实现vector
库中如何实现vector
50 0
|
2月前
|
存储 C++ 容器
C++入门8——vector的使用
C++入门8——vector的使用
107 0
|
4月前
|
安全 Java
Vector的使用
Vector的使用
23 2
|
5月前
|
Java C++ Python
vector类(上)
vector类(上)
49 0
|
5月前
|
Serverless C++ 容器
vector类(下)
vector类(下)
56 0
|
6月前
|
C++ 容器
【C++】学习笔记——vector_3
【C++】学习笔记——vector_3
27 0
|
6月前
|
Linux C++ 容器
【C++】学习笔记——vector_1
【C++】学习笔记——vector_1
37 0
|
6月前
|
人工智能 C++
【C++】学习笔记——vector_2
【C++】学习笔记——vector_2
25 0
|
C++ 容器
c++学习之vector的实现
c++学习之vector的实现
100 0
|
C++ 容器
C++中vector的用法
⭐一、vector的简介 vector的中文译为向量,因此vector是C++STL中一个向量类型的容器。vector还是C++STL中最常用也很实用的一个容器,它的功能十分的强大,可以容纳多种类型的数据。在一些特定的情况下普通的数组使用起来会比较局限,因为普通数组只能实现一对一的映射而不能实现一对多的映射,而vector的引入就可以很好的帮助我们解决这个问题。vector的大小是实时更新变化的,非常的灵活多用,因此vector也可以称之为动态数组。
213 0