准备知识
Vector集合实际上是实现了动态数组的方式,是可以随着向量元素的增加可以动态增长。实际上就是一种动态顺序表的应用。
属性
// Object类型的数组,用来存储实际数据
protected Object[] elementData;
说明:Vector底层实际存储数据的Object数组。
// 代表向量中元素的个数
protected int elementCount;
说明:Vector中elementData数组中存储元素的个数。
/**
* 向量的增长因数
* 当向量的容量大于其容量时,向量的容量自动递增的量。
* 如果容量增量小于或等于零,则每次需要增长时,向量的容量增加一倍。
*/
protected int capacityIncrement;
说明:Vector存储元素的容量大于其容量时,向量的容量自动递增的量。
构造方法
构造方法1:输入参数为初始化容量和增量参数的构造方法 。
public Vector(int initialCapacity, int capacityIncrement) {
super();
// 如果向量初始化容量小于0,那么就报非法参数异常的错误。
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
// 将初始化容量的长度作为Object数组实际长度
this.elementData = new Object[initialCapacity];
// 初始化增量参数
this.capacityIncrement = capacityIncrement;
}
构造方法2:使用指定的初始容量和等于零的容量增量构造一个空向量。
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
构造方法:构造一个初始化容量为10,增量为0的向量。
public Vector() {
this(10);
}
构造方法4:构造一个包含指定集合中的元素的向量,这些元素按其集合的迭代器返回元素的顺序排列。
public Vector(Collection extends E> c) {
// 将集合Collection转化为Object数组elementData。如果c为空,那么就会报空指针异常
elementData = c.toArray();
elementCount = elementData.length;
// 将c中的元素拷贝到elementData中
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
方法
ensureCapacity方法:扩充容量。
public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity > 0) {
modCount++;
ensureCapacityHelper(minCapacity);
}
}
说明:如果指定的容量大于0,那么就进行扩容操作。
private void ensureCapacityHelper(int minCapacity) {
// minCapacity为实际向量中的元素需要的容量,如果minCapacity大于当前数组长度,那么就进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
说明:如果指定容量大于了当前Vector中固定elementData数组的容量,就进行真正的扩容。
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// oldCapacity旧容量是Object数组的长度
int oldCapacity = elementData.length;
// 如果增量capacityIncrement大于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);
}
说明:如果capacityIncrement 增长因数大于0,那么扩容为原来的容量+capacityIncrement 。否则扩容为原来的2倍。
private static int hugeCapacity(int minCapacity) {
// 如果实际需要的容量小于0就抛出异常
if (minCapacity < 0)
throw new OutOfMemoryError();
// 实际容量如果比最大容量还大,那么实际容量为Integer.MAX_VALUE,否则为Integer.MAX_VALUE - 8
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
说明:如果扩容大于MAX_ARRAY_SIZE ,那么设置Integer.MAX_VALUE,否则设置为MAX_ARRAY_SIZE。
add方法:采用同步的方式往向量中添加元素e。
public synchronized boolean add(E e) {
modCount++;
// 由于添加元素需要动态的扩容,所以调用ensureCapacityHelper方法,长度要增长1
ensureCapacityHelper(elementCount + 1);
// 这步采用顺序表添加元素的模板代码,赋值长度加1
elementData[elementCount++] = e;
return true;
}
说明:如果elementCount + 1的容量大于数组的容量,将进行扩容;然后存储添加的值。
remove方法:删除指定下标的元素。
public synchronized E remove(int index) {
// Vector的修改次数加1
modCount++;
// 如果下标大于元素数量,就抛出数组下标超过异常
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 使用下标获取对应的旧值
E oldValue = elementData(index);
// 计算删除元素后,需要移动补位的元素的数量
int numMoved = elementCount - index - 1;
// 如果需要的数量大于0,那么拷贝元素
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 删除元素
elementData[--elementCount] = null; // Let gc do its work
// 返回旧值
return oldValue;
}
总结
1. Vector是线程安全的集合。
2. Vector可以存入null元素。
3. Vector可以存入重复元素。
4. Vector采用动态数组的方式实现的。
5. Vector默认的初始化容量为10,增量因子为0。
6. Vector扩容策略:如果Vector构造器中指定了增量因子capacityIncrement,那么Vector扩容为原容量+增量因子的大小。
如果未指定增量因子,那么Vector扩容为原来的2倍。