一、Vector 概述

  1、Vector 是 List 接口的另一个实现类: Vector

  2、Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。 

  3、Vector 的内部实现与 ArrayList 类似,也可以理解为一个【可变数组】。

    其继承结构如下:
    

 

 

  4、由于 Vector 目前使用较少,且官方也推荐在无线程安全的需求时使用 ArrayList 代替 Vector,这里仅研究其实现原理。

    stackoverflow 也有相关的讨论:

 

二、实现的接口

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 }   
    与 ArrayList 类似,Vector 内部也维护了一个 Object 类型的数组(elementData)来存储元素(默认初始容量也是10)。
    不同的是:Vector 比 ArrayList 的构造器多了一个参数 capacityIncrement,该变量也导致了二者的扩容方式略有不同。

 

  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);
    Vector 计算扩容后的新容量时,根据 capacityIncrement 的值可以分为两种情况:
    1. capacityIncrement > 0:新容量 = 旧容量 + capacityIncrement;
    2. capacityIncrement <= 0:新容量 = 旧容量 * 2。

 

    (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 关键字来保证同步,因此性能比较差。

  在各种list中,最好把ArrayList作为缺省选择。当插入、删除频繁时,使用LinkedList;Vector总是比ArrayList慢,所以尽量避免使用。

 

七、线程安全性

  Vector 是线程安全的,它实现线程安全的方式也很简单粗暴:直接在方法上使用 synchronized 关键字进行同步。

八、总结

  1、与 ArrayList 类似,Vector 也可以认为是【可变数组】;
  2、扩容原理与 ArrayList 基本一致,只是新容量计算方式略有不同;指定增长容量时,新容量为 旧容量 + 增长容量;否则扩容为旧容量的 两倍。
  3、线程安全的,实现方式简单(synchronized)

九、

十、

 

posted on 2021-04-19 10:32  格物致知_Tony  阅读(269)  评论(0编辑  收藏  举报