2019年一文读懂Vector

Vector


一、简介

Vector底层的数据结构是 “数组”,它会随着元素的增加而动态扩容,它是有序可重复、线程安全的集合,可存入多个 null 对象。Vector 是线程安全版的 ArrayList,它的基本增删改查操作方法都用 Synchronized 修饰。

1.1 源码分析
public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}

从源码分析,Vector 继承于 AbstractList,实现了 List,RandomAccess,Cloneable 和 Serializable 接口:

  1. 实现 List,并继承 AbstractList,获得集合接口 List 的基础功能;

  2. 实现 RandomAccess ,获得了快速随机访问存储元素的功能(RandomAccess 是一个标记接口,没有任何方法);

    // Collections类
    public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            return Collections.iteratorBinarySearch(list, key);
    }
    /**
     *区别:
     *  实现RandomAccess接口的List集合采用一般的for循环遍历,而未实现这接口则采用迭代器。
     *  Vector用for循环遍历比iterator迭代器遍历快,LinkedList用iterator迭代器遍历比for循环遍历快。
     */
    
  3. 实现 Cloneable,重写 clone,实现克隆功能;

  4. 实现 Serializable,可被序列化。

1.2 使用建议

当集合中有多线程对集合元素进行操作时候,则使用 Vector。但是现在 Vector 一般不再使用,如需在多线程下使用,可以用 java.util.concurrent.CopyOnWriteArrayList。

二、特点

2.1 初始化 Vector 的大小,未指定时默认是10
// 默认初始容量:10
public Vector() {
    this(10);
}

// 容量最大值:2147483647
Integer.MAX_VALUE

2.2 数据都存储在数组中
// 未加 transient,序列化时会记录elementData
protected Object[] elementData;

// 是动态数组的实际大小
protected int elementCount;

// 是动态数组的增长系数,默认为0(每次扩容为原大小的两倍)。
protected int capacityIncrement;

2.3 扩容
public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

private void ensureCapacityHelper(int minCapacity) {
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    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;
}
  • 第一种情况:默认构造函数
public Vector() {
    this(10);
}

默认构造函数初始化大小为10的数组,设定每次扩容为原来大小的两倍

不断存入元素会不断扩容,当 newCapacity 扩容量大于数组定义的最大阀值时,会调用 hugeCapacity 进行判断。如果待扩容大小已经超过 Integer 的最大值(溢出为负数),将抛出 OutOfMemoryError (内存溢出错误)。否则返回 Integer的最大值或 MAX_ARRAY_SIZE。故 Vector 的最大容量是 Integer 的最大值(-2的31次方~2的31次方减1)。

  • 第二种情况:自定义初始容量的构造函数
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}
  1. 当传入值 < 0 时,会抛出 IllegalArgumentException 异常;
  2. 当传入值 ≧ 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;
}

构造函数初始化指定大小的数组,并自定义每次扩容新增的大小。

  • 第四种情况:传入 Collection 集合方式的构造函数
public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    // 若elementData存储的是Object的子类,那么不做单独拷贝
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

  • 注意:为什么要将大小减8?

因为数据存储在数组中,有些虚拟机会在数组对象中额外存储一些信息(如描述对象状态的信息、对象是否同步的信息、数组的大小等),单独判断一次是为了避免内存溢出。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值