Vector源码的类注解:
- Vector类实现了一个可扩展的数组对象。像数组一样,它包含可以使用整数索引访问。Vector 是同步访问,的。Vector 包含了许多传统的方法,这些方法不属于集合框架。
- Vector 主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。
- 如果迭代时,数据发生了改变会,会快速的失败,抛出ConcurrentModificationException异常。
- Vector是线程安全的,可以放心使用,但是在不考虑线程安全的问题时,建议使用ArrayList替代.
Vector的成员变量:
/**
* Vector所在的数组缓冲区已存储
* Vector中最后一个元素之后的任何数组元素均为null
*/
protected Object[] elementData;
/**
*elementCount是Vector 对象中有效组件的数量。
*/
protected int elementCount;
/**
* Vector容量自动增加的量
*/
protected int capacityIncrement;
Vector初始化
- 传入带参的intialCapacity和capacity两个参数的初始化:
public Vector(int initialCapacity, int capacityIncrement) {
super();
// 校验intialCapacity数据合法性
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
- 传入intialCapacity的初始化方式:
public Vector(int initialCapacity) {
// 传入一个acpacityIncrement 为的0.
this(initialCapacity, 0);
}
- 无参构造初始化:
public Vector() {
// 此时initialCapacity 为默认值,而capacityIncrement为0.
this(10);
}
- 带初始数据的初始化:
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
// c.toArray可能(不正确)不返回Object [] (请参阅6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
其中see 6260652这是jdk的一个bug,意思为当给定的一个集合的元素不是Object类型时,我们将其转化为Object类型一般情况而言不会触发此bug,Vector源码已经经过修改不会触发此bug,注: 只有在下列场景下才会触发:Vector初始化之后(Vector元素非 Object 类型),再次调用 toArray 方法,得到 Object 数组,并且往 Object 数组赋值时,才会触发此 bug,
public static void main(String[] args) {
Vector<String> vector = new Vector<>();
vector.add("vector");
System.out.println(vector.getClass().getSimpleName());
Object[] array = vector.toArray();
System.out.println(array.getClass().getSimpleName());
array[0] = new Object();
}
正常输出,因为源码中已经做了修改。
Vector新增方法
新增的过层大致流程如下:
- 记录数组改变次数
- 检测数组的长度是否够用,不够用则进行扩容
- 直接把所需的添加元素添加到数组的后面
- 如果上诉几个步骤都没有抛出异常或者error表明已成功添加到数组中,返回true。
public synchronized boolean add(E e) {
// 用于记录数组的结构是否变动了
modCount++;
// j 检查数组的容量是否足够,不足过时进行扩容
ensureCapacityHelper(elementCount + 1);
// 追加到数组后面。
elementData[elementCount++] = e;
// 成功后返回true'
return true;
}
private void ensureCapacityHelper(int minCapacity) {
// 有溢出意识的代码,数组的长度是否足够添加,不满足则进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// 具体扩容过程
private void grow(int minCapacity) {
// 原有数组的长度
int oldCapacity = elementData.length;
// 如果初始化Vector的时候传入了一个capacityIncrement 则使用新数组的长度为老数组的长度 + capacityIncrement ,反之2×老的数组的长度
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
// 如果计算出新的数组的所需的长度小于传过来期望值,则使用传过来的期望值作为新数组所需的长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果大于 Integer.MAX_VALUE - 8 则继续调用hugeCapacity()方法,重新计算新数组
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 根据计算出新数组的长度并将老数组拷贝到新的数组中去,并重新赋值给elementData数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
// 如果最小的容量小于0则内存溢出
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// minCapacity 大于nteger.MAX_VALUE - 8 则返回Integer最大值,否则返回Integer.MAX_VALUE(最大值)
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
Vector的取值(get)方法
get方法大体流程:
- 检查传入的索引的合法性,
- 合法之后直接根据索引从数组elementData获取数据
源码如下:
public synchronized E get(int index) {
// 检查索引的合法性 主要是否超出数组的长度
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
// 根据索引从数组取出数据
E elementData(int index) {
return (E) elementData[index];
}
Vector的删除(remove)方法
remove方法大体流程:
- 检查要删除的索引是否合法
- 合法后通过从数组中直接取出待删除元素的将其存为一个临时变量存起来
- 计算出要删除个数,并将要待删除数据往前移动,把数组最后一个置为null.
- 返回要删除元素的值。
public synchronized E remove(int index) {
// 记录数组变化
modCount++;
// 检查数索引的合法性,是否超过数组的长度
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 将所需要删除的元素用一个临时量存起来。
E oldValue = elementData(index);
// 计算需要搬移的元素个数。
int numMoved = elementCount - index - 1;
// 如果不是数组的吼吼一个元素,则将所需要删除的数据后面的数据往前移。
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 将数组的最后一个置为null
elementData[--elementCount] = null; // Let gc do its work
// 返回要删除的元素
return oldValue;
}
总结:
- Vector整体的架构就是数组 + synchronized锁实现的,每个操作到数组的方法都加了synchrony修饰保证其线程安全。
- 由于是通过同步锁实现的,性能在大多数情况是不如ArrayList好,在不靠线程安全问题的建议使用ArrayList代替。
- 涉及到新增或者删除批量数据直接只用addAll()或者removeAll(),避免数组频繁扩容或者数组搬移。