集合源码解析之Vector

概述

在前两章我们已经学习了List常用的两个实现ArrayListLinkedList,下面我们来学习下Vector.VectorArrayList一样是基于数组实现的List,区别在于Vector是线程安全的,我们来研究下其源码.Vector和ArrayList配合食用,味道更佳哦...

源码分析

结构图

继承关系

public class Vector
    extends AbstractList
    implements List, RandomAccess, Cloneable, java.io.Serializable{}

VectorArrayList一样实现了List``RandomAccess``Cloneable``java.io.Serializable接口,继承了AbstractList类.

类中属性

/** 和ArrayList一样,这个是核心数组 */
protected Object[] elementData;

/** 元素数量(Vector的实际容量) */
protected int elementCount;

/** 扩容因子 */
protected int capacityIncrement;

/** 版本号 */
private static final long serialVersionUID = -2767605614048989439L;

/** AbstractList里的属性, 记录集合 涉及到结构变化的次数(add/remove/clear等) */
protected transient int modCount = 0;

类中的属性也和ArrayList相差不多,内部维护Object[]数组来存储元素,和ArrayList唯一的区别是多了个capacityIncrement变量.至于这个变量是干什么的,咱们继续往下看.

构造函数

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;
}

/** 构造器 设置初始容量 */
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}

/** 无参构造器 设置初始容量10 */
public Vector() {
    this(10);
}

/** 创建包含指定集合 */
public Vector(Collection 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);
}

几个构造函数区别不大,都是进行初始化容量,数据和扩容因子capacityIncrement.

核心函数

由于接口实现较多,各个功能的多个实现核心差不多,这里挑选每种功能里核心的来讲解.如想深入每个函数,请自行
翻阅源码.

添加函数

/** 在指定下标位置上插入元素 */
public synchronized void insertElementAt(E obj, int index);

/** 插入一个元素 */
public synchronized void addElement(E obj);

/**  添加一个元素 */
public synchronized boolean add(E e);

/** 在指定位置上插入一个元素 */
public void add(int index, E element);

/** 将指定的元素集从index下标开始插入到Vector中 */
public synchronized boolean addAll(int index, Collection c);
synchronized void addElement(E obj)
/** 插入一个元素 */
public synchronized void addElement(E obj) {
    modCount++;
    // 触发扩容
    ensureCapacityHelper(elementCount + 1);
    // 赋值
    elementData[elementCount++] = obj;
}

addElement(E obj)代码比较简单,触发扩容,然后赋值.再来看看扩容代码

/** 扩容的中间调用 */
private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        // 扩容核心方法
        grow(minCapacity);
}

/** Vector 扩容的实际方法 */
private void grow(int minCapacity) {
    // 大小
    int oldCapacity = elementData.length;

    // 如果 capacityIncrement 大于0,则每次递增 capacityIncrement 个,
    // 否则 容量翻倍.
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);

    // 如果新设的容量小于 minCapacity(最小容量限制),则新设容量等于 minCapacity
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;

    // 设置 容量的 最大限制
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);

    // 进行扩容
    elementData = Arrays.copyOf(elementData, newCapacity);
}

/** 最大容量限制 */
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

实际上扩容的代码和ArrayList也是差不多的, 唯一的区别体现于扩容容量.ArrayList每次扩容为其原本容量的0.5倍,而Vector则是根据扩容因子capacityIncrement来计算每次容量的增长,如果capacityIncrement小于0,每次扩容为原本容量的一倍.若大于0,每次容量增加capacityIncrement个.

synchronized void insertElementAt(E obj, int index)
    /**  在指定下标位置上插入元素 */
    public synchronized void insertElementAt(E obj, int index) {
        modCount++;
        if (index > elementCount) {
            throw new ArrayIndexOutOfBoundsException(index
                                                     + " > " + elementCount);
        }
        // 触发扩容
        ensureCapacityHelper(elementCount + 1);
        // 往后挪
        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
        // 赋值
        elementData[index] = obj;
        elementCount++;
    }
synchronized boolean addAll(int index, Collection c)
    /** 把指定的集合的所有元素添加到Vector中 */
    public synchronized boolean addAll(Collection c) {
        modCount++;
        Object[] a = c.toArray();
        int numNew = a.length;
        // 扩容
        ensureCapacityHelper(elementCount + numNew);
        // 进行copy
        System.arraycopy(a, 0, elementData, elementCount, numNew);
        // 设置新的元素数量
        elementCount += numNew;
        return numNew != 0;
    }

获取函数

/** 获取元素 */
public synchronized E get(int index) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    return elementData(index);
}

/** 返回数组指定下标的元素 */
E elementData(int index) {
    return (E) elementData[index];
}

修改函数

/**
 * 给指定位置设置新元素,并且返回旧元素
 */
public synchronized E set(int index, E element) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    // 获取旧的元素
    E oldValue = elementData(index);
    // 重新赋值
    elementData[index] = element;
    return oldValue;
}

删除函数

    /**
     * 根据下标删除一个元素,并返回此元素
     *
     * 实现逻辑和ArrayList的类似
     */
    public synchronized E remove(int index) {
        modCount++;
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        E oldValue = elementData(index);

        int numMoved = elementCount - index - 1;
        if (numMoved > 0)
            // 把index+1后的所有元素拷贝一份从index位置开始
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // 同时删除最后一个多余的元素(拷贝后导致的最后一个元素的重复出现(最后一个和倒数第二个元素是重复的))
        elementData[--elementCount] = null; // Let gc do its work

        return oldValue;
    }

Vector里的函数和ArrayList基本上类似,没什么需要特别讲的.注意Vector供外部访问的函数均被synchronized关键字所修饰属于线程安全的.

和ArrayList对比

  • Vector是线程安全的,而ArrayList不是,从源码可以看出Vector中很多函数被synchronized修饰,虽然这赋予了Vector的线程安全的特性,但也导致Vector在效率上无法和ArrayList相比.
  • Vector和ArrayList采用的都是数组存储,当空间不足进行扩容时,ArrayList每次扩容是原容量的0.5倍,而Vecotr则是自定义每次扩容的增长量,默认为1倍.

注意

现在官方已经不推荐使用Vector了,Vector被认为是Java中的遗留类.
Vector在JDK1.0中首次引入,后来经过改进又实现了List接口,尽管它现在已经是集合大家庭的一员,但它很少在新项目中被使用,仅处于向后兼容而受支持.
根据Vector的java文档,如果不需要使用线程安全的实现,建议使用ArrayList代替Vector.
如果需要使用线程安全的集合,则可以使用CopyOnWriteArrayList,也可以使用Collections.synchronizedList()通过外部方式把ArrayList变为线程安全的(仅限于原子操作).

你可能感兴趣的:(集合源码解析之Vector)