天天看点

【JDK源码】Vector源码分析

Vector类也是List集合的一种类型,源码分析将与ArrayList类对比进行。

目录

1、构造方法

2、扩容机制

3、遍历删除时的陷阱、迭代器、分割器

4、其他方法

1、构造方法

源码分析如下:

public class Vector<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    /** 对象数组 */
    protected Object[] elementData;
    /** Vector集合的大小 */
    protected int elementCount;
    /** 容量步进 */
    protected int capacityIncrement;

    /** 
     * Vector集合有下面四种构造器:无参,指定容量大小,指定容量大小+容量步进,指定集合 
     **/
    public Vector() {this(10);}  //①
    public Vector(int initialCapacity) {this(initialCapacity, 0);}  //②
    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(Collection<? extends E> c) {  //④
        // 保证传入集合非null,否则报NPE
        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);
    }  
}
           

小结一下:

与ArrayList集合相比,Vector集合同样:

  • 继承了AbstractList类,实现了List接口, RandomAccess接口, Cloneable接口,Serializable接口;
  • 底层也维护了一个对象数组Object[]来存储元素,且元素是有序、可重复的存储;
  • 构造器也有无参,指定容量大小,指定集合对象等入参形式。

不同的是:

  • Vector集合构造器多了一个重载(即第③种),入参多了容量步进capacityIncrement,该参数用于扩容计算;
  • Vector集合是直接在构造器内进行指定默认容量大小10,而ArrayList集合在使用add()方法添加元素时才初始化默认容量为10。

2、扩容机制

Vector集合通过add()方法添加元素时,会触发自动扩容操作,源码分析如下:

public class Vector<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    /**
     *  以add(E e)方法为例,Vector集合扩容的关键步骤如下:
     *     add()方法是一个synchronized方法
    **/
    public synchronized boolean add(E e) {
        modCount++;
        // 1.添加元素到数组前先进行判断是否需要扩容
        ensureCapacityHelper(elementCount + 1);
        // 6.将该元素存放在数组上,size自加1标识Vector集合中元素添加了1个
        elementData[elementCount++] = e;
        return true;
    }

    /** 2.超过数组大小,通过grow()方法扩容 */
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /** 数组最大容量 */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 3.扩容计算方式:步进>0 —— oldCapacity*2 ;步进<=0 ——  oldCapacity + capacityIncrement 。
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        // 4.扩容后对象数组大小出现以下两种情况,则重新赋值扩容后对象数组大小
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 5.通过数组拷贝方式,实现自动扩容
        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;
    }

    /**
     *  add(int index, E e):是将元素插入到指定位置,也需要扩容判断
     *     也是一个synchronized方法
    **/
    public void add(int index, E element) {
        insertElementAt(element, 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++;
    }

    /**
     *  addAll():两个集合求并集,同样需要扩容判断
     *      也是一个synchronized方法
    **/
    public synchronized boolean addAll(Collection<? extends E> c) {
        modCount++;
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityHelper(elementCount + numNew); // 扩容判断
        System.arraycopy(a, 0, elementData, elementCount, numNew);
        elementCount += numNew;
        return numNew != 0;
    }

    /**
     *  addElement():向Vector集合追加内容
     *      也是一个synchronized方法
    **/
    public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }

    /**
     *  setSize():重置Vector集合大小
     *      也是一个synchronized方法
    **/
    public synchronized void setSize(int newSize) {
        modCount++;
        if (newSize > elementCount) {
            ensureCapacityHelper(newSize);
        } else {
            for (int i = newSize ; i < elementCount ; i++) {
                elementData[i] = null;
            }
        }
        elementCount = newSize;
    }
}
           

小结一下:

  • Vector集合将默认容量10放在了构造器中,其余的关键扩容步骤与ArrayList集合是一样的,只是扩容计算公式不同而已 —— Vector集合按照两倍A 或者 A+B的方式扩容,ArrayList集合按照1.5倍扩容!
  • 与ArrayList集合相比,Vector集合的add()方法、addAll()方法、setSize()方法、addElement()方法均是同步的,因此多线程环境中进行相关操作是线程安全的!

3、遍历删除时的陷阱、迭代器、分割器

遍历删除时的陷阱:

与ArrayList集合相比,Vector集合自身也有两个删除的方法:remove(int index)、remove(Object o),除了remove()是synchronized的,实现删除逻辑与ArrayList集合也是一样的!同样的,foreach遍历使用集合自身删除方法时,仍然存在ConcurrentModificationException异常,原因也是Iterator源码中的next()方法中存在 checkForComodification()方法,它会检查预期修改次数expectedModCount 和实际修改次数modCount 是否一致,不一致会报并发修改异常。因此,建议使用Iterator的remove()方法遍历删除!!!

迭代器:

迭代器Iterator和列表迭代器ListIterator的使用也适用于Vector集合,除了相关操作是synchronized的,实现逻辑均是一致的。

在Vector集合遍历循环时容易引发ConcurrentModificationException异常的方法有:(modCount变量存在的地方都有可能引发并发修改异常!!)

  • trimToSize()、setSize()、clear()、add()、addAll()、remove()等方法用在遍历时;
  • Java8新增的方法:forEach()、removeIf()、sort()、replaceAll()等等。

分割器Spliterator:

Vector集合的分割器Spliterator,类似ArrayList集合的分割器,源码逻辑实现类似。

public class Vector<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    @Override
    public Spliterator<E> spliterator() {
        return new VectorSpliterator<>(this, null, 0, -1, 0);
    }

    /** Similar to ArrayList Spliterator */
    static final class VectorSpliterator<E> implements Spliterator<E> {
        private final Vector<E> list;
        private Object[] array;
        private int index; // current index, modified on advance/split
        private int fence; // -1 until used; then one past last index
        private int expectedModCount; // initialized when fence set

        /** Create new spliterator covering the given  range */
        VectorSpliterator(Vector<E> list, Object[] array, int origin, int fence,
                          int expectedModCount) {
            this.list = list;
            this.array = array;
            this.index = origin;
            this.fence = fence;
            this.expectedModCount = expectedModCount;
        }
        private int getFence() {...;}
        public Spliterator<E> trySplit() {...;}
        public boolean tryAdvance(Consumer<? super E> action) {...;}
        public void forEachRemaining(Consumer<? super E> action) {...;}
        public long estimateSize() {return (long) (getFence() - index);}
        public int characteristics() {
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }
    }
}
           

4、其他方法

Vector集合其余的操作方法,大多数都是synchronized的,并发操作是线程安全的!!!

public class Vector<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    // 将Vector集合的元素拷贝到指定数组中
    public synchronized void copyInto(Object[] anArray) {System.arraycopy(elementData, 0, anArray, 0, elementCount);}
    // Vector集合当前容量
    public synchronized int capacity() {return elementData.length;}
    // Vector集合的大小
    public synchronized int size() {return elementCount;}
    // 集合判空
    public synchronized boolean isEmpty() {return elementCount == 0;}
    // 判断集合是否包含指定对象
    public boolean contains(Object o) {return indexOf(o, 0) >= 0;}
    // 是一种浅克隆,不会将原集合的元素拷贝到新的集合
    public synchronized Object clone() {...;}
    // 重写equals方法
    public synchronized boolean equals(Object o) {return super.equals(o);}
    // 重写hashCode方法
    public synchronized int hashCode() {return super.hashCode();}
    // 重写toString方法
    public synchronized String toString() {return super.toString();}
    // Vector集合转对象数组
    public synchronized Object[] toArray() {return Arrays.copyOf(elementData, elementCount);}
    // Vector集合转泛型数组,由运行时确定数组类型
    public synchronized <T> T[] toArray(T[] a) {...;}
    // 查找元素在集合中的位置(顺序查找)
    public synchronized int indexOf(Object o, int index) {...; return -1;}
    // 查找元素在集合中的位置(倒序查找)
    public synchronized int lastIndexOf(Object o, int index) {...; return -1;}
    // 返回Vector集合的第一个元素
    public synchronized E firstElement() {...; return elementData(0);}
    // 返回Vector集合最后的一个元素
    public synchronized E lastElement() {...; return elementData(elementCount - 1);}
    // 返回Vector集合中指定索引位置的元素
    public synchronized E elementAt(int index) {...; return elementData(index);}
    // 在Vector集合中指定位置修改元素
    public synchronized void setElementAt(E obj, int index) {...; elementData[index] = obj;}
    // 从指定范围,截取生成新的子集合
    public synchronized List<E> subList(int fromIndex, int toIndex) {
        return Collections.synchronizedList(super.subList(fromIndex, toIndex), this);
    }
}
           

小结

Vector集合作为List集合的实现类,从底层实现的元素存储,自动扩容机制,迭代器和列表迭代器,到分割器等与ArrayList集合最为相似了。而最大的不同就是线程安全问题,从以上的源码不难发现,Vector集合的方法几乎都是同步方法,能保证并发操作集合时是安全的。但同步方法锁住的是整个方法,高并发场景中会显得并发操作效率低的问题,因此优先推荐使用J.U.T包下的 CopyOnWriteArrayList集合来操作List集合类型的数据。不积硅步无以至千里,点滴付出终将有所收获,共同进步 ~

继续阅读