概述
Vector是JDK 1.0中引入的一个集合,具有和ArrayList一样的功能, 但是在平时的开发过程中很少使用,我们可能仅限于知道它是一个线程安全的有序集合,那它为什么基本上被我们程序员淘汰了呢?
Vector介绍
Vector 是一个有序的集合容器,可以进行自动扩容,而且它是线程安全的。
以上是Vector的类图:
- 继承了AbstractList,该类封装了List的基本操作
- 实现了List接口,表明是一个有序列表
- RandomAccess 是一个标记接口,用于标记实现该接口的集合支持快速随机访问。
- Serializable 是一个标记接口,用于标记实现该接口的类可以序列化。
- Cloneable 是一个标记接口,用于标记实现该接口的类可以调用 clone 方法,否则会抛异常。
构造方法:
- public Vector(int initialCapacity,int capacityIncrement)
说明:Vector 运行时创建一个初始的存储容量initialCapacity,存储容量是以capacityIncrement 变量定义的增量增长。初始的存储容量和capacityIncrement 可以在Vector 的构造函数中定义。
public Vector(int initialCapacity)
说明:构造函数只创建初始存储容量
public Vector()
说明:既不指定初始的存储容量也不指定capacityIncrement,默认的初始容量是10
关键方法:
基本都是List接口的方法,用来操作集合数据,不做阐述。
核心机制
扩容机制
区别于ArrayList,每次扩容是当前容量的1.5倍,Vector是根据构造函数传入的capacityIncrement
参数来确定每次增加的容量,如果传入的capacityIncrement
为0或者不传入,每次扩容是当前容量的2倍。
FailFast机制
虽然Vector是一个线程安全的容器,但是它仅限于单个方法,比如add方法。
在Vector 是哦那个Iterator遍历的过程中,其他线程操作Vector,比如添加或者删除元素,都有可能导致迭代遍历出现未知的错误,这种快速失败做出响应,抛出ConcurrentModificationException异常就是fail fast。
源码解析
我们重点就关注下add方法,看下它是如何扩容的。
// synchronized关键字表明方法是同步的 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; // 新的容量=原来的容量 + 增加的容量, 这里增加的容量如果为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); }
总结
回过头来,我们在想想为什么不推荐大家使用这个Vector容器了?
- 因为vector是线程安全的, 用synchronized关键字,所以效率低;
- Vector空间满了之后,默认情况下扩容是一倍,而ArrayList仅仅是一半;
- Vector分配内存的时候需要连续的存储空间,如果数据太多,容易分配内存失败;
至于线程安全的同类容器,我推荐可以用jdk1.5引入的CopyOnWriteArrayList
。