容器源码分析之——Vector

一、Vector简介

1.1 类继承结构

Alt Text

1.2 数据结构

Alt Text

二、源码

2.1 注释

  Vector与ArrayList是非常相似的,注释中的说明也是类似的,可参考上篇博文“ArrayList源码阅读”。注释中有这样一句话:“Vector是同步的,如果不需要线程安全的实现,推荐使用ArrayList代替Vector”。

2.2 定义

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

类定义与类继承结构图是对应的。
从中我们可以了解到:

  • Vector:说明它支持泛型。
  • extends AbstractList :继承了AbstractList。AbstractList提供List接口的骨干实现,以最大限度地减少“随机访问”数据存储(如ArrayList)实现Llist所需的工作。
  • implements List:实现了List。实现了所有可选列表操作。
  • implements RandomAccess:表明Vector支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。
  • implements Cloneable:表明其可以调用clone()方法来返回实例的field-for-field拷贝。
  • implements java.io.Serializable:表明该类具有序列化功能。

2.3 域

     /**
     * 保存vector元素的数组,数组的长度就是vector的容量,vector的容量至少要能
     * 保存所有的元素
     *
     * <p>任何在vector最后一个元素之后的数组元素都是null
     *
     * @serial
     */
    protected Object[] elementData;

    /**
     * vector中的实际元素数
     * {@code elementData[elementCount-1]} are the actual items.
     *
     * @serial
     */
    protected int elementCount;

    /**
     * vector在自动扩容时增加的容量,当vector的实际容量将要大于它的最大容量时,vector自动增加的容量
     * 当该值<=0时,vector的容量需要扩容时就扩为原来的2倍
     *
     * @serial
     */
    protected int capacityIncrement;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -2767605614048989439L;

查看上面源码中的注释即可,比较简单。

2.4 构造方法

    /**
     * 构造一个指定初始容量为initialCapacity,自增容量为capacityIncrement的空vector
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

    /**
     * 构造一个指定初始容量为initialCapacity,自增容量为0的空vector
	 * 实际上里面调用的是上一个构造函数
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    /**
     * 构造一个指定初始容量为10,自增容量为0的空vector
     * 实际上调用的是上一个构造函数
     */
    public Vector() {
        this(10);
    }

    /**
     * 使用指定的Collection构造vector
     * @throws NullPointerException if the specified collection is null
     * @since   1.2
     */
    public Vector(Collection<? extends E> c) {
        elementData = c.toArray();
        elementCount = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }

共有四个构造函数

  1. public Vector(int initialCapacity, int capacityIncrement)
  2. public Vector(int initialCapacity)
  3. public Vector()
  4. public Vector(Collection<? extends E> c)

2.5 核心方法

Vector类所有被外部访问到的方法,都是线程同步的,实现方法是“synchronized”的关键字。举几个栗子

2.5.1 copyInto(object[] anArray)
    /**
     * 将vector的所有元素复制进指定的数组anArray中
     * The item at index {@code k} in this vector is copied into
     * component {@code k} of {@code anArray}.
     *
     * @param  anArray the array into which the components get copied
     * @throws NullPointerException if the given array is null
     * @throws IndexOutOfBoundsException if the specified array is not
     *         large enough to hold all the components of this vector
     * @throws ArrayStoreException if a component of this vector is not of
     *         a runtime type that can be stored in the specified array
     * @see #toArray(Object[])
     */
    public synchronized void copyInto(Object[] anArray) {
        System.arraycopy(elementData, 0, anArray, 0, elementCount);
    }

方法被synchronized关键字修饰。

2.5.2 trimToSize()

    /**
     * 将底层数组的容量调整为当前vector实际元素的个数,来释放空间
     */
    public synchronized void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
		//当实际元素个数小于底层数组的长度
        if (elementCount < oldCapacity) {
			//将底层数组的长度调整为实际大小
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }

** 小结:Vector与ArrayList的最大不同就是它的方法是线程同步的,实现同步的方式就是用“synchronized”修饰方法。**

2.6 扩容机制

    /**
     * 为保证vector可以容纳所有需要容纳的元素,在必要时进行扩容
     * 扩容规则:
     * 1、capacityIncrement大于0时,新的容量将在旧的容量的基础上加上capacityIncrement;
	 * 小于0时,增加到原来的2倍。
	 * 2、如果新的容量还是小于至少需要的容量,则将容量扩容为至少需要的容量。
	 * 3、如果至少需要的容量大于MAX_ARRAY_SIZE,则进行大容量分配,hugeCapacity()函数中进行
     * @param minCapacity the desired minimum capacity
     */
    public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }
	/**
	* ensureCapacity()方法的unsynchronized实现。
	* 
	* ensureCapacity()是同步的,它可以调用本方法来扩容,而不用承受同步带来的消耗
	* 
	* @see #ensureCapacity(int)
	*/
	private void ensureCapacityHelper(int minCapacity) {
    // 如果至少需要的容量 > 数组缓冲区当前的长度,就进行扩容
		if (minCapacity - elementData.length > 0)
			grow(minCapacity);
	}
	/**
	* 分派给arrays的最大容量
	* 为什么要减去8呢?
	* 因为某些VM会在数组中保留一些头字,尝试分配这个最大存储容量,可能会导致array容量大于VM的limit,最终导致OutOfMemoryError。
	*/
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;


** 小结:ArrayList和Vector的扩容逻辑稍微有些不同。vector的逻辑是: newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); 即如果capacityIncrement>0,就加capacityIncrement,如果不是就增加一倍。
而ArrayList的逻辑是:
newCapacity = oldCapacity + (oldCapacity >> 1); 即增加现有的一半。
后面的大容量分配逻辑是一样的。**

posted @ 2021-01-31 23:44  CleverZiv  阅读(73)  评论(0编辑  收藏  举报