容器(七):垂垂老矣Vector
标签: Java编程思想
Vector是List家族里的老资格了,在JDK1.0,还没有List的时候,Vector就已经开始为Collection家族效力了,在JDK1.2以后,并入到List中。随着时间的变迁,这个第一代容器早已经打上了“不推荐使用”的标签。
一道面试题
之前看过一篇面经,问题是ArrayList和Vector的区别:
ArrayList,Vector主要区别为以下几点:
- Vector是线程安全的,源码中有很多的synchronized可以看出,而ArrayList不是。导致Vector效率无法和ArrayList相比;
- ArrayList和Vector都采用线性连续存储空间,当存储空间不足的时候,ArrayList默认增加为原来的50%,Vector默认增加为原来的一倍;
- Vector可以设置capacityIncrement,而ArrayList不可以,从字面理解就是capacity容量,Increment增加,容量增长的参数。
Vecotor唯一的优势就是线程安全,但是现在有Collections.synchronizedListt方法拿同步的List,因此不推荐使用Vector了。
什么是Vector
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
Vector 和 ArrayList 一样,都是继承自 AbstractList。它是 Stack 的父类。英文的意思是 “矢量”。
Vector 成员变量
//底层也是个数组
protected Object[] elementData;
//数组元素个数
protected int elementCount;
//扩容时增长数量,允许用户自己设置。如果这个值是 0 或者 负数,扩容时会扩大 2 倍,而不是 1.5
protected int capacityIncrement;
//给定一个最大的容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
Vector 的构造方法
默认无参构造器
实际上是调用含参数的构造器,只是默认的数组容量为10:
//创建默认容量 10 的数组,同时增长量为 0
public Vector() {
this(10);
}
指定容量构造器
实际上是调用指定容量和增长量的构造器,只是默认的增长量为0:
//创建一个用户指定容量的数组,同时增长量为 0
public Vector(int capacity) {
this(capacity, 0);
}
指定容量和增长量的构造器
我们通过构造函数可以看出,Vector的底层是一个Object类型的数组,指定了扩容时的增长量。
//创建指定容量大小的数组,设置增长量。如果增长量为非正数,扩容时会扩大两倍
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)
//可能有这个神奇的 bug,用 Arrays.copyOf 重新创建、复制
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
Vector中的扩容方法
与ArrayList.grow(int) 很相似,只是扩大量不同:
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;
}
Vector的添加元素的方法
确保容量
检查数量,准备扩容
private void ensureCapacityHelper(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
其他方法
因为Vector不怎么用了,而且方法很多,我就不想挨个去看源码了。要用的时候查阅API就好了
Vector遍历
Vector支持4种遍历方式。
随机访问
因为Vector实现了RandmoAccess接口,可以通过下标来进行随机访问。
for(int i = 0 ; i < vec.size() ; i++){
value = vec.get(i);
}
迭代器
Iterator it = vec.iterator();
while(it.hasNext()){
value = it.next();
//do something
}
for循环
for(Integer value:vec){
//do something
}
Enumeration循环
Vector vec = new Vector<>();
Enumeration enu = vec.elements();
while (enu.hasMoreElements()) {
value = (Integer)enu.nextElement();
}
总结
Vector 特点:
- 底层由一个可以增长的数组组成
- Vector 通过 capacity (容量) 和 capacityIncrement (增长数量) 来尽量少的占用空间
- 扩容时默认扩大两倍
- 最好在插入大量元素前增加 vector 容量,那样可以减少重新申请内存的次数
- 通过 iterator 和 lastIterator 获得的迭代器是 fail-fast 的
- 通过 elements 获得的老版迭代器 Enumeration 不是 fail-fast 的
同步类,每个方法前都有同步锁 synchronized
Vector VS ArrayListde 共同点:
- 都是基于数组
- 都支持随机访问
- 默认容量都是 10
- 都有扩容机制
Vector VS ArrayListde 区别:
- Vector 出生的比较早,JDK 1.0 就出生了,ArrayList JDK 1.2 才出来
- Vector 比 ArrayList 多一种迭代器 Enumeration
- Vector 是线程安全的,ArrayList 不是
- Vector 默认扩容 2 倍,ArrayList 是 1.5
其实现在不管有没有线程安全都需求,都不推荐使用Vector。
ps:用心学习,喜欢的话请点赞 (在左侧哦)