Java小白集合源码的学习系列:Vector

Vector源码学习

前文传送门:
Java小白集合源码的学习系列:LinkedList
Java小白集合源码的学习系列:ArrayList
Vector是JDK1.0中的集合,是集合中的老大哥,其中大部分的方法都被synchronized关键字所修饰,与ArrayList和LinkedList不一样,它是线程安全的(关于线程安全,以后学习再作系统总结)。可是随着一系列的更新迭代,它的缺点渐渐暴露:如方法名字太长,实现接口时出现了许多重复多余的方法等等。
从JDK1.2开始,Vector类被改进以实现List接口,让它成为Java集合框架的一员,若是不须要线程安全,建议使用ArrayList,效率更高。java

Vector继承体系

仍是按照惯例,先看看它的继承图,固然这张图是基于JDK1.8的。
1SwsaV.png数组

  • 能够看出来它和ArrayList同样,继承了AbstractList,实现List接口。
  • 实现了RandomAccess接口,支持随机访问。
  • 实现了Cloneable接口,实现了克隆的功能。
  • 实现了Serializable接口,支持序列化。

Vector核心源码

基本属性

//存储元素的数组
    protected Object[] elementData;
    //元素个数
    protected int elementCount;

    //该值决定了增加机制的不一样
    protected int capacityIncrement;
    private static final long serialVersionUID = -2767605614048989439L;

构造器

咱们能够得出结论:Vector的底层也是基于数组实现的,可是这些属性和咱们以前提到的ArrayList有什么不一样之处呢?咱们继续向下看它所提供的几个构造器:安全

//两个参数,建立initialCapacity大小的数组,并为capacityIncrement赋值
    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, int capacityIncrement)
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    //无参构造器,调用Vector(int initialCapacity)
    public Vector() {
        this(10);
    }

    //传入集合
    public Vector(Collection<? extends E> c) {
        elementData = c.toArray();
        elementCount = elementData.length;
        //类型判断
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }

咱们能够发现:框架

  • initialCapacity表明的是数组的容量,咱们能够指定容量,不指定默认为10
  • capacityIncrement从字面上看,就能够知道它表明的是容量增量,意味着这个值将会影响以后的扩容,能够指定,不指定默认为0。

扩容机制

那么咱们继续来看看它的扩容机制,是否能够验证咱们的说法:
基本上的部分,都是和ArrayList相似,咱们直接截取有差别的部分:dom

private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //若是增量大于0,新容量 = 原容量 + 增量
        //若是增量不大于0,新容量 = 原容量*2
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

其余的部分就不作分析了,以前讲的很详细,能够看看前面的文章。咱们须要关注的是:ide

  • 若是指定增量(增量>0),那么每次在扩容的时候,新容量就是在原容量的基础上加上指定增量
  • 若是没有指定增量,那么每次在扩容的时候,新容量默认变成原容量的两倍

Enumeration

概述

提及迭代器,咱们老是第一个想到的就是Iterator,而再Iterator是在JDK1.2的时候诞生的,用于取代JDK1.0版本的惟一迭代器Enumeration。官方对它的解释是这样的:学习

An object that implements the Enumeration interface generates a series of elements, one at a time. Successive calls to the nextElement method return successive elements of the series.this

我用拙劣的英语试着翻译一下:实现Enumeration这个接口的对象呢,将会生成一系列的元素,生成的时候是一个一个生成的,经过调用nextElement这个方法,就能够返回这个系列里全部的连续元素。.net

今天咱们励志作个光荣的官方文档搬运工!

Methods are provided to enumerate through the elements of a vector, the keys of a hashtable, and the values in a hashtable. Enumerations are also used to specify the input streams to a SequenceInputStream.

这段的意思也很明白:Enumeration接口为Vector的元素hashtable的键和值提供了枚举的方法,它也被运用到指定SequenceInputStream的输入流中。咱们暂时只须要知道,Vector类中,有一种方法可以产生Eumeration对象就完事了。其余的咱们后面会进行总结。

接下来这段话至关关键!官方文档中用了大写的NOTE:

NOTE:The functionality of this interface is duplicated by the Iterator interface. In addition, Iterator adds an optional remove operation, and has shorter method names. New implementations should consider using Iterator in preference to Enumeration.

大体的意思就是:如今这个方法呢,不太适应潮流了,那个年代用起来挺不错,如今须要年轻一辈来代替了。这个新一代的产物就是Iterator,它复制了Enumeration的功能,而且增长可选的remove操做,并且提供了更简短的命名。官方仿佛在嬉皮笑脸对你说:亲,这边建议你迭代器尽可能用Iterator哟。

可是尽管如此,咱们还需须要了解如下它的基本操做,毕竟之后可能仍是会见到。

源码描述

//Enumeration接口  
public interface Enumeration<E> {
    //判断是否还有更多的元素
    boolean hasMoreElements();
    //没有下一个元素就报错,有就返回
    E nextElement();
}
//Vector中的elements方法对接口的实现
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");
        }
    };
}

具体操做

Vector<String> v = new Vector<>();
    v.add("天");
    v.add("乔");
    v.add("巴");
    v.add("夏");
    //利用vector对象产生迭代器对象
    Enumeration<String> e = v.elements();
    //判断后边是否还有元素
    while(e.hasMoreElements()){
        //挪动指针指向下一个元素
        System.out.print(e.nextElement()+" ");
    }
    //天 乔 巴 夏

Vector总结

  • 底层基于数组,能够实现动态扩增,支持根据索引快速访问。
  • 若是没有指定容量,默认为10。若是没有指定增量,默认为0。
  • 扩容时,若是增量>0,则新容量=指定增量+原容量;若是增量<=0,则新容量为原容量的两倍。(注意,Vector里也有实现肯定容量的方法ensureCapacity)
  • 线程安全,如在建立迭代器以后的任什么时候间对结构进行修改,除了迭代器自己的remove和add外,都会抛出ConcurrentModification异常。因此,Vector经过synchronized关键字实现线程同步。能够参考:https://blog.csdn.net/yjclsx/article/details/85283169

本文如有叙述不当之处,还望各位评论区加以批评指正,谢谢。

参考资料:JDK1.8官方文档

相关文章
相关标签/搜索