返回

Vector剖析:揭开动态数组的底层奥秘

后端

  1. Vector简介

Vector是Java集合框架中的一个动态数组,它允许你存储任意类型的对象。与普通数组不同的是,Vector可以自动扩容,这意味着当你往Vector中添加元素时,它会自动增加容量以容纳更多元素。

Vector是一个线程安全的集合类,这意味着它可以同时被多个线程访问而不会产生数据错乱。这使得Vector非常适合在多线程环境中使用。

Vector的特点包括:

  • 动态数组:Vector可以自动扩容,以容纳更多元素。
  • 线程安全:Vector可以同时被多个线程访问而不会产生数据错乱。
  • 继承自AbstractList:Vector继承自AbstractList,这意味着它提供了List接口的所有方法。

2. Vector的实现

Vector的底层实现是一个数组,这个数组被称为elementData。当Vector需要存储更多元素时,它会自动创建一个更大的数组,并将元素从旧数组复制到新数组中。

Vector的容量(capacity)是指它可以容纳的最大元素数量。当Vector的容量不够时,它会自动扩容,扩容后容量会增加一倍。

Vector的扩容操作可能会导致性能下降,因此,在使用Vector时,应该尽量预估需要存储的元素数量,并将其容量设置为一个合理的值。

3. Vector的源码分析

public class Vector<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, Serializable {

    /**
     * The array buffer into which the elements of the Vector are stored.
     * The capacity of the Vector is the length of this array buffer.
     */
    protected transient Object[] elementData;

    /**
     * The number of valid components in the Vector.
     */
    protected int elementCount;

    /**
     * The amount by which the capacity of the Vector is automatically
     * incremented when its size becomes greater than its capacity.
     */
    protected int capacityIncrement;

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

    /**
     * Constructs an empty vector with the specified initial capacity and
     * capacity increment.
     *
     * @param initialCapacity     the initial capacity of the vector
     * @param capacityIncrement   the amount by which the capacity of the vector
     *                           is automatically incremented when its size becomes
     *                           greater than its capacity
     * @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;
    }

    /**
     * Constructs an empty vector with an initial capacity of 10.
     */
    public Vector() {
        this(10);
    }

    /**
     * Constructs a vector containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this
     *          vector
     * @throws NullPointerException if the specified collection is null
     */
    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);
    }

    /**
     * Trims the capacity of this Vector to be the current size.
     * If the capacity is larger than the size, then the capacity is changed
     * to be equal to the size.
     *
     * This method is useful when you know that the Vector will no longer grow
     * and you want to conserve space.
     */
    public synchronized void trimToSize() {
        modCount++;
        if (elementCount < elementData.length) {
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }

    /**
     * Returns the current capacity of this Vector.
     *
     * @return  the current capacity of this Vector
     */
    public synchronized int capacity() {
        return elementData.length;
    }

    /**
     * Increases the capacity of this Vector, if necessary, to ensure
     * that it can hold at least the number of elements specified by
     * the minimum capacity argument.
     *
     * @param   minCapacity   the desired minimum capacity
     */
    public synchronized void ensureCapacity(int minCapacity) {
        modCount++;
        if (minCapacity > elementData.length) {
            elementData = Arrays.copyOf(elementData,
                                        Math.max(minCapacity, elementCount + capacityIncrement));
        }
    }

    /**
     * Sets the capacity of this Vector to the specified number of elements.
     * If the new capacity is less than the current capacity, then the capacity
     * is not changed.
     *
     * @param   newCapacity   the new capacity of this Vector
     * @throws IllegalArgumentException if the new capacity is less than the
     *              current size of this Vector
     * @since   1.2
     */
    public synchronized void setSize(int newCapacity) {
        modCount++;
        if (newCapacity > elementCount) {
            elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            if (newCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   newCapacity);
            elementData = Arrays.copyOf(elementData, newCapacity);
            elementCount = newCapacity;
        }
    }

    /**
     * Copies the components of this Vector into the specified array. The
     * array must be big enough to hold all of the elements of this Vector.
     *
     * @param anArray the array into which the components get copied
     * @throws NullPointerException if the specified array is null
     * @throws IndexOutOfBoundsException if the specified array is not large
     * enough to hold all of the elements of this Vector
     * @since   1.2
     */
    public synchronized void copyInto(Object[] anArray) {
        System.arraycopy(elementData, 0, anArray, 0, elementCount);
    }

    /**
     * Returns an array containing all of the elements in this Vector. The
     * returned array will be safe to modify without affecting this Vector.
     *
     * @since   1.2
     */
    public synchronized Object[] toArray() {
        return Arrays.copyOf(elementData, elementCount);
    }

    // Most Stack methods are not implemented, but must appear in the class

    /**
     * Pushes an element onto the stack represented by this Vector.
     *
     * @param o   the element to be pushed onto the stack
     * @return   the argument passed in
     * @see Vector#pop
     * @since   1.0
     */
    public synchronized E push(E o) {
        addElement(o);
        return o;
    }

    /**
     * Removes the object at the top of the stack represented by this Vector.
     *
     * @return   The object at the top of the stack
     * @see Vector#push
     * @since   1.0
     */
    public synchronized E pop() {
        E obj;
        int len = elementCount - 1;
        if (len < 0) {
            throw new EmptyStackException();
        }
        obj = elementData[len];
        elementData[len] = null;  // Eliminate obsolete reference
        elementCount--;
        return obj;
    }

    /**
     * Returns the object at the top of the stack represented by this Vector.
     *
     * @return  the object at the top of the stack
     * @see Vector#pop
     * @since   1.0
     */
    public synchronized E peek() {
        int len = elementCount - 1;
        if (