Java集合类源码解析:Vector

引言

之前的文章我们学习了一个集合类 ArrayList,今天讲它的一个兄弟 Vector

为什么说是它兄弟呢?因为从容器的构造来说,Vector 简直就是 ArrayList 的翻版,也是基于数组的数据结构,不同的是,Vector的每个方法都加了 synchronized 修饰符,是线程安全的。

类声明

用idea打开 Vector 的源码,不难发现,它的类声明跟 ArrayList 一模一样,都是继承了AbstractList,并且都实现了RandomAccess 接口,遍历元素用for循环的效率要优于迭代器。

 * @author  Lee Boynton
 * @author  Jonathan Payne
 * @see Collection
 * @see LinkedList
 * @since   JDK1.0
 */
public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

值得说明的是,从注释上来看,Vector 是 JDK1.0版本就引进的,属于最古老的集合类的那一批,而ArrayList是 1.2才引进的,所以说,Vector才是哥哥,ArrayList是小弟,哈哈~~~~

基本变量和构造函数

基本变量

Vector 的基本变量有四个,分别是:

  • 底层数组
protected Object[] elementData;
  • 数组元素个数
protected int elementCount;
  • 增长的容量大小,如果这个值小于或等于0,扩容时会扩大 2 倍,
capacityIncrement
  • 最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

构造函数

//创建初识容量为10的数组,增长量0
public Vector() {
    this(10);
}
//创建初识容量可变的数组,增长量为0
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) {
    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);
 }

看的出来,Vector的构造器和成员变量和ArrayList大同小异。

成员方法

扩容

Vector 与 ArrayList 虽然很类似,但在扩容大小这方面还是有区别的,ArrayList 默认扩容后的大小为原容量 的1.5倍,而Vector则是先判断增长量大小,如果是非正数,那就扩大为原来的2倍,看一下它的扩容方法:

//参数是最小需要的容量
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //如果增长量不大于0,扩容为2倍大小
    //一般默认创建的容器都是不传增长量的,所以默认增长量是0,也就是默认直接扩容两倍
    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);
}
private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

添加

Vector的添加方法都是加上 synchronized关键字的,并且添加前检测容量,判断是否扩容:

//加入元素到数组结尾,同步的
public synchronized boolean add(E e) {
    modCount++;
    //检测容量
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}
//检测容量大小,超过数组长度就做扩容
private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
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++;
    }
public synchronized void addElement(E obj) {
    modCount++;
    //保证容量足够
    ensureCapacityHelper(elementCount + 1);
    //直接设置最后一个元素的数据
    elementData[elementCount++] = obj;
}
//添加整个集合
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);
        //复制元素数组
        System.arraycopy(a, 0, elementData, index, numNew);
        elementCount += numNew;
        return numNew != 0;
    }

Vector的添加方法代码不是很复杂,跟ArrayList 一样,本质上都是对数组做插入数据的操作,不同的是,方法都加了synchronized 修饰,所以,它的添加方法都是线程安全的。

其他操作元素的方法也是这样的套路,这里不打算一一列举了,因为都跟ArrayList 差不多,另外,Vector 比 ArrayList 多了一个迭代方法

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

返回的是一个Enumeration 接口对象,大概也是个容器接口,没用过,不说太多。

Vector 对比 ArrayList

最后,总结一下 Vector 和 ArrayList 的对比吧。

相同点:

  • 底层都是基于数组的结构,默认容量都是10;
  • 都实现了RandomAccess 接口,支持随机访问;
  • 都有扩容机制;

区别:

  • Vector 的方法有做同步操作,是属于线程安全的,而ArrayList 是非线程安全的;
  • Vector默认情况下扩容后的大小为原来的2倍,而ArrayList 是1.5倍;
  • Vector 比 ArrayList 多了一种迭代器 Enumeration;

虽然Vector相较ArrayList做了同步的处理,但这样也影响了效率,因为每次调用方法都要获取锁,所以,一般情况下,对集合的线程安全没有需求的话,推荐使用 ArrayList。

原文地址:https://www.cnblogs.com/yeya/p/9970654.html

时间: 2024-11-07 05:24:47

Java集合类源码解析:Vector的相关文章

Java集合类源码解析:AbstractMap

目录 引言 源码解析 抽象函数entrySet() 两个集合视图 操作方法 两个子类 参考: 引言 今天学习一个Java集合的一个抽象类 AbstractMap ,AbstractMap 是Map接口的 实现类之一,也是HashMap.TreeMap.ConcurrentHashMap 等的父类,它提供了Map 接口中方法的基本实现(关于Map接口有疑惑的同学可参考 Java集合类根接口:Collection 和 Map) 源码解析 因为 AbstractMap 类是实现Map接口的抽象类,所以

Java集合类源码解析:LinkedHashMap

前言 今天继续学习关于Map家族的另一个类 LinkedHashMap .先说明一下,LinkedHashMap 是继承于 HashMap 的,所以本文只针对 LinkedHashMap 的特性学习,跟HashMap 相关的一些特性就不做进一步的解析了,大家有疑惑的可以看之前的博文. 深入解析 LinkedHashMap的基本结构 首先,看一下LinkedHashMap类的定义结构: public class LinkedHashMap<K,V> extends HashMap<K,V&

Java集合类源码解析:AbstractList

今天学习Java集合类中的一个抽象类,AbstractList. 初识AbstractList AbstractList 是一个抽象类,实现了List<E>接口,是隶属于Java集合框架中的 根接口 Collection 的分支,由其衍生的很多子类因为拥有强大的容器性能而被广泛应用,例如我们最为熟悉的ArrayList,这是它的类继承结构图: 特殊方法 AbstractList 虽然是抽象类,但其内部只有一个抽象方法 get(): abstract public E get(int index

java 集合类源码分析--Vector

首先我们来看JDK源码中Java.util.Vector的代码,剔除所有的方法和静态变量, Java.lang.Vector的核心代码如下: public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { protected Object[] elementData; /** * The number of

【转】Java HashMap 源码解析(好文章)

- .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wrapper iframe, .fluid-width-video-wrapper object, .fluid-width-video-wrapper embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } [

java集合类源码剖析

java集合类源码剖析 hashmap 底层实现 HashMap.Entry数组,数组+拉链 static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; Entry<K,V> next; final int hash; } Entry对象代表了HashMap中的一个元素(键值对) hashCode相同(碰撞)的元素将分配到Entry数组的同一个桶中 同一个桶中的Entry对象由nex

java 集合类源码分析--linkedlist

一.源码解析 1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clone()与toArray()9.遍历数据:Iterator()二.ListItr 一.源码解析 1. LinkedList类定义. public class LinkedList<E> extends AbstractSequentialList<E> implements List

Java String源码解析

String类概要 所有的字符串字面量都属于String类,String对象创建后不可改变,因此可以缓存共享,StringBuilder,StringBuffer是可变的实现 String类提供了操作字符序列中单个字符的方法,比如有比较字符串,搜索字符串等 Java语言提供了对字符串连接运算符的特别支持(+),该符号也可用于将其他类型转换成字符串. 字符串的连接实际上是通过StringBuffer或者StringBuilder的append()方法来实现的 一般情况下,传递一个空参数在这类构造函

java集合 源码解析 学习手册

学习路线: http://www.cnblogs.com/skywang12345/ 总结 1 总体框架 2 Collection架构 3 ArrayList详细介绍(源码解析)和使用示例 4 fail-fast总结(通过ArrayList来说明fail-fast的原理.解决办法) 5 LinkedList详细介绍(源码解析)和使用示例 6 Vector详细介绍(源码解析)和使用示例 7 Stack详细介绍(源码解析)和使用示例 8 List总结(LinkedList, ArrayList等使用