一、Vector 概述
1、Vector 是 List 接口的另一个实现类: Vector
2、Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。
3、Vector 的内部实现与 ArrayList 类似,也可以理解为一个【可变数组】。
4、由于 Vector 目前使用较少,且官方也推荐在无线程安全的需求时使用 ArrayList 代替 Vector,这里仅研究其实现原理。
二、实现的接口
1 public class Vector<E>
2 extends AbstractList<E>
3 implements List<E>, RandomAccess, Cloneable, java.io.Serializable
可以发现,Vector 实现的接口同 ArrayList,作用也是一致的。
三、成员变量
1 /**
2 * The array buffer into which the components of the vector are
3 * stored. The capacity of the vector is the length of this array buffer,
4 * and is at least large enough to contain all the vector's elements.
5 *
6 * <p>Any array elements following the last element in the Vector are null.
7 *
8 * @serial
9 */
10 protected Object[] elementData; //存储数据的数组
11
12 /**
13 * The number of valid components in this {@code Vector} object.
14 * Components {@code elementData[0]} through
15 * {@code elementData[elementCount-1]} are the actual items.
16 *
17 * @serial
18 */
19 protected int elementCount; //有效元素的个数
20
21 /**
22 * The amount by which the capacity of the vector is automatically
23 * incremented when its size becomes greater than its capacity. If
24 * the capacity increment is less than or equal to zero, the capacity
25 * of the vector is doubled each time it needs to grow.
26 *
27 * @serial
28 */
29 protected int capacityIncrement; //容量增长因子
30
31 /** use serialVersionUID from JDK 1.0.2 for interoperability */
32 private static final long serialVersionUID = -2767605614048989439L;
33
34 /**
35 * The maximum size of array to allocate.
36 * Some VMs reserve some header words in an array.
37 * Attempts to allocate larger arrays may result in
38 * OutOfMemoryError: Requested array size exceeds VM limit
39 */
40 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
四、构造器
Vector 对外提供四个构造器(内部可以认为是两个)
1、方式一:
1 protected Object[] elementData;
2
3 protected int capacityIncrement;
4
5 // 无参构造器
6 public Vector() {
7 this(10);
8 }
9
10 // 指定容量的构造器
11 public Vector(int initialCapacity) {
12 this(initialCapacity, 0);
13 }
14
15 // 指定初始容量和容量增长因子的构造器
16 public Vector(int initialCapacity, int capacityIncrement) {
17 super();
18 if (initialCapacity < 0)
19 throw new IllegalArgumentException("Illegal Capacity: "+
20 initialCapacity);
21 this.elementData = new Object[initialCapacity];
22 this.capacityIncrement = capacityIncrement;
23 }
2、方式二:入参为集合的构造器
1 public Vector(Collection<? extends E> c) {
2 Object[] a = c.toArray();
3 elementCount = a.length;
4 if (c.getClass() == ArrayList.class) {
5 elementData = a;
6 } else {
7 elementData = Arrays.copyOf(a, elementCount, Object[].class);
8 }
9 }
五、Vector 扩容原理分析
1、从构造函数分析
(1)从上面构造器可以发现以无参数构造方法创建 Vector 时,实际上初始化赋值的是一个容量为10的数组,扩容因子是0。
(2)还可以指定容量,就会创建一个容量为指定的数组,此时的数组扩容因子是 0。
(3)也可以同时指定容量和扩容因子,会创建一个指定容量的数组,扩容因子为设置的值。
2、一步一步分析 Vector 扩容机制
这里以无参构造函数创建的 ArrayList 为例分析
(1)先来看 add
方法(addAll()方法类似)
1 /**
2 * 将指定的元素追加到此列表的末尾。
3 */
4 public synchronized boolean add(E e) {
5 //添加元素之前,先调用ensureCapacityHelper方法
6 modCount++;
7 ensureCapacityHelper(elementCount + 1); //确保内部容量
8 //这里看到ArrayList添加元素的实质就相当于为数组赋值
9 elementData[elementCount++] = e;
10 return true;
11 }
可以看到,在 add() 方法执行时,会首先执行 ensureCapacityHelper 方法
注意这里的关键字 synchronized。观察可以发现:Vector 内部许多方法都使用了该关键字,这也是 Vector 实现线程安全的方式,简单粗暴!
(2)查看 ensureCapacityHelper() 方法
该方法是非同步的,因为 Vector 内部调用该方法的地方都使用了 synchronized 关键字进行同步,这里不再额外使用
1 private void ensureCapacityHelper(int minCapacity) {
2 // overflow-conscious code
3 //判断是否需要扩容,如果所需容量大于目前数组长度,则进行扩容
4 if (minCapacity - elementData.length > 0)
5 grow(minCapacity);
6 }
(3)grow()方法
源码:
1 /**
2 * Vector 扩容的核心方法。
3 */
4 private void grow(int minCapacity) {
5 // overflow-conscious code
6 // oldCapacity为旧容量,newCapacity为新容量
7 int oldCapacity = elementData.length;
8
9 //如果指定了扩容因子 capacityIncrement,则在原来容量上扩容
10 //如果没有指定扩容因子,则扩容为2倍容量
11 int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
12 capacityIncrement : oldCapacity);
13
14 //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
15 if (newCapacity - minCapacity < 0)
16 newCapacity = minCapacity;
17
18 // 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) hugeCapacity() 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,
19 //如果minCapacity大于最大容量,则新容量则为Integer.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE 即为Integer.MAX_VALUE - 8。
20 if (newCapacity - MAX_ARRAY_SIZE > 0)
21 newCapacity = hugeCapacity(minCapacity);
22 elementData = Arrays.copyOf(elementData, newCapacity);
23 }
从这里可以看出,Vector 与 ArrayList 的扩容方式基本一致,只是新容量的计算方式有所不同,这里分析下其新容量大小:
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
(4)hugeCapacity()方法(巨大的容量)
从上面 grow()
方法源码我们知道: 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) hugeCapacity()
方法来比较 minCapacity 和 MAX_ARRAY_SIZE,如果 minCapacity 大于最大容量,则新容量则为Integer.MAX_VALUE
,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 Integer.MAX_VALUE - 8
。
1 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
2
3 private static int hugeCapacity(int minCapacity) {
4 if (minCapacity < 0) // overflow
5 throw new OutOfMemoryError();
6 return (minCapacity > MAX_ARRAY_SIZE) ?
7 Integer.MAX_VALUE :
8 MAX_ARRAY_SIZE;
9 }
3、
4、
5、
六、常用方法
Vector 与 ArrayList 常用方法几乎类似,只是在方面上面添加了 synchronized 关键字来保证同步,因此性能比较差。
七、线程安全性
Vector 是线程安全的,它实现线程安全的方式也很简单粗暴:直接在方法上使用 synchronized 关键字进行同步。
八、总结
九、
十、