Vector源码学习(JDK8)

面试时,考官总喜欢问ArrayList和Vector的区别,前面我学习了ArrayList源码,在描述里有这样一句话:

(This class is roughly equivalent to <tt>Vector</tt>, except that it is unsynchronized.)
这个类与Vector类似,但是它是不同步的。

通过这我们就知道Vector与ArrayList的最大区别了,但是呢这并不影响我们点进Vector源码进行学习。文章内容有不正确之处,欢迎大家指正,共同学习,共同进步!

首先,我们还是按之前的套路来==、,先看看描述:


 /** The {@code Vector} class implements a growable array of
 * objects. Like an array, it contains components that can be
 * accessed using an integer index. However, the size of a
 * {@code Vector} can grow or shrink as needed to accommodate
 * adding and removing items after the {@code Vector} has been created.*/
 vector类实现了一个可增长的对象数组。与数组一样,它包含了可以通过使用整数索引进行访问的组件。
但是,vector的大小可以根据需要来扩大或减小,以便于创建vector后添加和删除内容。
 /** <p>Each vector tries to optimize storage management by maintaining a
 * {@code capacity} and a {@code capacityIncrement}. The
 * {@code capacity} is always at least as large as the vector
 * size; it is usually larger because as components are added to the
 * vector, the vector's storage increases in chunks the size of
 * {@code capacityIncrement}. An application can increase the
 * capacity of a vector before inserting a large number of
 * components; this reduces the amount of incremental reallocation.*/
 任何vector试图通过维护容量和容量增量来优化存储管理,它的容量总是至少与vector大小一样大;通常
它会更大,因为随着组件被添加到vector中,vector的存储随着容量增量大小来增长。
 /** <p><a name="fail-fast">
 * The iterators returned by this class's {@link #iterator() iterator} and
 * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em></a>:
 * if the vector is structurally modified at any time after the iterator is
 * created, in any way except through the iterator's own
 * {@link ListIterator#remove() remove} or
 * {@link ListIterator#add(Object) add} methods, the iterator will throw a
 * {@link ConcurrentModificationException}.  Thus, in the face of
 * concurrent modification, the iterator fails quickly and cleanly, rather
 * than risking arbitrary, non-deterministic behavior at an undetermined
 * time in the future.  The {@link Enumeration Enumerations} returned by
 * the {@link #elements() elements} method are <em>not</em> fail-fast.*/
  快速失败
  这个类通过iterator和listIterator方法返回的迭代器是快速失败的。如果vector在迭代器创建后发生了
结构改变,无论何时、以任何方式(除了迭代器自身的添加和删除方法),迭代器都会抛出并发修改异常。因
此,面对并发修改,迭代器会快速且利落的失败,而不是在未来的不确定时间冒任意,非确定性行为的风险。
 /** <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
 * as it is, generally speaking, impossible to make any hard guarantees in the
 * presence of unsynchronized concurrent modification.  Fail-fast iterators
 * throw {@code ConcurrentModificationException} on a best-effort basis.
 * Therefore, it would be wrong to write a program that depended on this
 * exception for its correctness:  <i>the fail-fast behavior of iterators
 * should be used only to detect bugs.</i>*/
 注意快速失败行为并不是迭代器自身保证的那样,一般来讲,存在不同步并发修改时不可能做出任何确切的
保证。因此,为了保证其准确性而编写一个依赖该异常的程序是错误的。迭代器的快速失败行为应该只用来
检测问题。
 /** <p>As of the Java 2 platform v1.2, this class was retrofitted to
 * implement the {@link List} interface, making it a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.  Unlike the new collection
 * implementations, {@code Vector} is synchronized.  If a thread-safe
 * implementation is not needed, it is recommended to use {@link
 * ArrayList} in place of {@code Vector}.*/
在java2平台v1.2上,这个类被改造以成实现List接口,使其成为了Java Collections Framework的一个
成员。与新的集合实现不同,vector是同步的,如果不是线程安全实现的需要,建议使用ArrayList来替换
Vector。

上面描述里声明:如果不是线程安全需要,我们还是尽量使用ArrayList,因为Vector是同步的,这也就导致其效率相对与ArrayList会低很多。

跟ArrayList一样,Vector继承AbstractList<E>类并实现了List<E>, RandomAccess, Cloneable, java.io.Serializable接口

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

 然后我们简单看一下类中对应的变量和构造方法:

变量:

    //存放数据的对象数组
    protected Object[] elementData;
    //元素数量
    protected int elementCount;
    //容量增量
    protected int capacityIncrement;
    //序列化ID
    private static final long serialVersionUID = -2767605614048989439L;

构造方法:

    (1)带初始化容量及容量增量参数的构造函数:
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)//判断初始化容量大小的合法性
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
    //创建以传入的容量大小的对象数组
        this.elementData = new Object[initialCapacity];
    //设置增长值为传入的增量大小
        this.capacityIncrement = capacityIncrement;
    }
    (2)带初始化容量参数的构造函数:
    public Vector(int initialCapacity) {
    //调用上面构造函数,只是将增量设置为0
        this(initialCapacity, 0);
    }
    (3)无参构造
    public Vector() {
    //调用上面构造函数,设置默认容量为10
        this(10);
    }
    (4)以集合为参数的构造函数:(与ArrayList类似)
    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、copyInto(Object[] anArray) :复制vector内容到新的数组中

    /**
     * Copies the components of this vector into the specified array.
     * The item at index {@code k} in this vector is copied into
     * component {@code k} of {@code anArray}.
     */
    将vector组件拷贝到新建的数组中。vector索引对应的项目复制到anArray的component {@code k}中
    public synchronized void copyInto(Object[] anArray) {
        System.arraycopy(elementData, 0, anArray, 0, elementCount);
    }

2、trimToSize():调整vector容量,保证vector容量始终为合适大小。程序可以使用这个方法来最小化vector存储。

    /**
     * Trims the capacity of this vector to be the vector's current
     * size. If the capacity of this vector is larger than its current
     * size, then the capacity is changed to equal the size by replacing
     * its internal data array, kept in the field {@code elementData},
     * with a smaller one. An application can use this operation to
     * minimize the storage of a vector.
     */    
    public synchronized void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (elementCount < oldCapacity) {
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }

3、扩容操作函数:

    public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }

    根据传入的容量大小判断是否超过集合长度,若超过则扩容
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        //判断容量增量是否为0,若为0则扩容为当前容量的2倍,若不为0则扩容为当前容量+容量增量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)//判断扩容后大小是否大于最大数组大小,大于则执行 hugeCapacity()函数。
            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;
    }

4、setSize(int newSize): 设置vector大小

    /**Sets the size of this vector. If the new size is greater than the
    * current size, new {@code null} items are added to the end of
    * the vector. If the new size is less than the current size, all
    * components at index {@code newSize} and greater are discarded.*/
    设置当前vector大小,如果新的vector大小大于当前vector,则将当前vector的数据拷贝到新的vector中,若小于,则丢弃新索引对应的所有组件。
    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;
    }

5、capacity():获取vector容量 

    public synchronized int capacity() {
        return elementData.length;//返回elementData长度
    }

6、size() :获取vector组件个数

    public synchronized int size() {
        return elementCount;//返回元素个数
    }

7、isEmpty():判断vector是否为空 

    public synchronized boolean isEmpty() {
        return elementCount == 0;//为0则返回true
    }

8、elements():返回该vector组件的枚举,枚举对象包含vector的所有值,第一个值就是索引0对应的内容,接着就是索引1对应的内容,以此类推。

    /**
     * Returns an enumeration of the components of this vector. The
     * returned {@code Enumeration} object will generate all items in
     * this vector. The first item generated is the item at index {@code 0},
     * then the item at index {@code 1}, and so on.
     */
    public Enumeration<E> elements() {
        return new Enumeration<E>() {//返回一个枚举对象
            int count = 0;

            public boolean hasMoreElements() {//判断是否有下一个元素
                return count < elementCount;
            }

            public E nextElement() {
                synchronized (Vector.this) {
                    if (count < elementCount) {
                        return elementData(count++);//依次返回索引对应数据
                    }
                }
                throw new NoSuchElementException("Vector Enumeration");
            }
        };
    }

 9、contains(Object o):判断是否包含对象,通过循环遍历比对。

    public boolean contains(Object o) {
        return indexOf(o, 0) >= 0;
    }

    public synchronized int indexOf(Object o, int index) {
        if (o == null) {
            for (int i = index ; i < elementCount ; i++)//循环遍历比对
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index ; i < elementCount ; i++)
                if (o.equals(elementData[i]))//循环比对
                    return i;
        }
        return -1;
    }

10、indexOf(Object o):返回对象对应的索引

    public int indexOf(Object o) {
        return indexOf(o, 0);
    }
    //循环遍历匹配对象在返回对象对应的索引
    public synchronized int indexOf(Object o, int index) {
        if (o == null) {
            for (int i = index ; i < elementCount ; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index ; i < elementCount ; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

 

11、elementAt(int index)—指定索引对应的数据;firstElement()—第一个数据;lastElement()最后一个数据

    //这几个方法对索引或组件数量进行了判断,若不合法则抛出异常。
    public synchronized E elementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }

        return elementData(index);
    }

    public synchronized E firstElement() {
        if (elementCount == 0) {
            throw new NoSuchElementException();
        }
        return elementData(0);
    }

    public synchronized E lastElement() {
        if (elementCount == 0) {
            throw new NoSuchElementException();
        }
        return elementData(elementCount - 1);
    }

12、add(E e):在vector最后位置添加一个元素;addAll(Collection<? extends E> c):在vector最后依次添加集合内元素;addAll(int index, Collection<? extends E> c)在指定索引位置开始依次添加集合内元素,并将索引后面的原始数据往后移动集合内元素个数的位数。

    //插入一个元素
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);//判断是否需要扩容
        elementData[elementCount++] = e;//vector里添加一个元素
        return true;
    }

    //插入一个集合
    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;
    }

    //在指定索引位置开始依次插入集合内元素
    public synchronized boolean addAll(int index, Collection<? extends E> c) {
        modCount++;
        if (index < 0 || index > elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityHelper(elementCount + numNew);

        int numMoved = elementCount - index;//得出移动位数
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);//原索引位置数据依次向后移动numMoved位

        System.arraycopy(a, 0, elementData, index, numNew);//原集合元素与新插入元素形成的集合复制为一个新的集合
        elementCount += numNew;//原元素个数+集合内元素数量
        return numNew != 0;
    }

13、remove(Object o):删除元素,实际是通过removeElementAt(index)删除( 删除前调用indexOf(obj)获取元素对应索引),删除后将后面元素向前移动一位,并将最后一个索引对应的值置为null(elementData[elementCount] = null),供垃圾回收器回收;removeAllElements():循环将索引对应元素置为空供垃圾回收器回收,并将元素个数置为0;clear():清除所有内容,实际执行removeAllElements()

    删除一个:
    public boolean remove(Object o) {
        return removeElement(o);
    }
    
    public synchronized boolean removeElement(Object obj) {
        modCount++;
        int i = indexOf(obj);//获取索引
        if (i >= 0) {
            removeElementAt(i);
            return true;
        }
        return false;
    }

    public synchronized void removeElementAt(int index) {
        modCount++;
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        int j = elementCount - index - 1;
        if (j > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, j);//删除位置后面元素向前移动一位
        }
        elementCount--;
        elementData[elementCount] = null; /* to let gc do its work */ //供垃圾回收器回收
    }

    删除集合所有元素
    public synchronized void removeAllElements() {
        modCount++;
        // Let gc do its work
        for (int i = 0; i < elementCount; i++)
            elementData[i] = null;

        elementCount = 0;
    }

    //清除
    public void clear() {
        removeAllElements();
    }
    

14、set(int index, E element):替换指定索引位置的元素

    public synchronized E set(int index, E element) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        E oldValue = elementData(index);
        elementData[index] = element;//将指定索引位置元素替换
        return oldValue;
    }

 15、iterator():vector迭代与arrayList方法基本相同,这里就不展开来讲,有疑问的小伙伴可以查看我的文章:ArrayList源码学习(JDK8)

总结:通过ArrayList与Vector的源码分析对比,我们不难发现两者实现方式极其相似。不过Vector的每个方法中都添加了synchronized的关键字来保证同步,所以它是线程安全的,因此也导致其效率大大降低。在之前的描述中已经提到,若非线程安全需要,我们尽可能使用ArrayList。

以上是我基于JDK8的Vector源码学习,在这里记录下来,希望同大家交流学习,欢迎大家指出其中不足之处,谢谢!

下期预告:LinkedList源码学习(基于jdk8)。

 

传送门:

            1、ArrayList源码学习(JDK8)

            2、LinkedList源码学习(JDK8)

如果喜欢本文,请为我点赞,您的支持是我继续下去的动力,您也可以在评论区与我探讨或指正错误,最后别忘了关注一下我哦,谢谢。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值