一、什么是Vector?
Vector和ArrayList一样是一个集合,都实现了List接口
二、Vector的源码分析
我们首先看一下Vector中的几个属性:
// 从这里我们可以看出Vector其实也是一个数组
protected Object[] elementData;
// elementCount等价与ArrayList的size
protected int elementCount;
// 每次扩容增加的大小
protected int capacityIncrement;
接下来看一下Vector的构造函数:
// 这是无参构造
public Vector() {
// 这里调用了另一个构造,设置集合的默认大小为10
this(10);
}
// 上面的无参构造调用了这个有参构造
public Vector(int initialCapacity) {
// 继续套娃这个也调用了一个有参构造
this(initialCapacity, 0);
}
// 上面的有参构造调用了这个有参构造
// initialCapacity默认长度;capacityIncrement每次扩容增加的大小
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
// 这个用的比较少就不介绍了如果想了解这个可以看一下我的ArrayList的介绍
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
接下来分析一下常用的方法,如果大家基础比较好或者对这里没有什么兴趣的话可以直接看vector的扩容方法
// 最常用的添加方法
// synchronized 这里使用了锁,证明是线程安全的
public synchronized boolean add(E e) {
// 这个modCount其实是AbstractList<E>这个类继承下来的
// 作用和ArrayList一样都是记录修改次数的初始是0
modCount++;
// 这个方法是看vector是不是需要进行扩容
ensureCapacityHelper(elementCount + 1);
// 这就是数组的添加:
// 第一次添加默认是0执行之后++变为1
elementData[elementCount++] = e;
return true;
}
// get获取传递过来的Index这个索引下的值
public synchronized E get(int index) {
// 查询的索引是否大于集合最大索引如果大于抛出异常
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 如果不大于则返回查询索引下的值
return elementData(index);
}
// set修改这个索引下的值,并返回旧的值
public synchronized E set(int index, E element) {
// 这里同get一样
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 获取当前索引下旧的值
E oldValue = elementData(index);
// 把新的值赋给这个索引
elementData[index] = element;
// 返回旧的值
return oldValue;
}
// 查看集合中是否有这个值,从index索引到最大索引
// 是左开右闭
// 其他的indexof都是重载了这个方法
public synchronized int indexOf(Object o, int index) {
// 判断是否有这个值
if (o == null) {
// 没有进入这步循环查看从index-elementCount之间的索引
// 这个区间有没有某个索引的值为null
for (int i = index ; i < elementCount ; i++)
// 如果有就返回这个索引且如果有多个只返回第一个
if (elementData[i]==null)
return i;
}
// 如果有这个值,就看值是否在Index-elementCount这个索引区间里
// 如果在就返回索引
else {
for (int i = index ; i < elementCount ; i++)
if (o.equals(elementData[i]))
return i;
}
// 都不存在就返回-1
return -1;
}
// 这个就是重载了上面的indeof从所有索引里查找
public int indexOf(Object o) {
return indexOf(o, 0);
}
// 这个是从后往前查找里面内容我就不介绍了和indexof的没啥区别
public synchronized int lastIndexOf(Object o, int index) {
if (index >= elementCount)
throw new
IndexOutOfBoundsException(index + " >= "+ elementCount);
if (o == null) {
for (int i = index; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = index; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
三、Vector的扩容
前面大致讲解了一些比较常用的方法,现在开始我要讲解一下Vector的扩容方法了:
public synchronized boolean add(E e) {
modCount++;
// 进入这个方法来看是否需要进行扩容
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
private void ensureCapacityHelper(int minCapacity) {
/*
如果在初始化的时候是使用无参构造的话,那么这里默认的集合
大小就是10所以elementData.length的长度为10;
那么在这里就需要看你添加的参数是不是大于10个,如果
大于10个就进入扩容方法grow()里
*/
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// 为扩容前的长度或者说集合的大小
int oldCapacity = elementData.length;
// 扩容后的长度或者说集合的大小
// 通过三元运算符:如果capacityIncrement > 0
// 那么就返回capacityIncrement如果小于或等于0就返回oldCapacity
// 最后扩容前的长度+三元运算符最后返回的参数就是扩容后的长度
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
// 如果扩容后的长度小于当前传入参数的大小则扩容后的长度就等于传入的参数
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 最后通过Arrays.copyof方法来生成新的数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
四、Vector和ArrayList的区别
1、线程安全上
通过Vector和ArrayList的源码上我们发现Vector的方法上基本都加了synchronized同步锁,而ArrayList的方法上没有,所以我们很明确的就可以得出Vector是线程安全的,而ArrayList是线程不安全的,不过也因为Vector是线程安全的所以效率上是不如ArrayList的
2、扩容方法上
通过源码分析我们可以得出ArrayList的扩容是按照初始长度的1.5倍来进行扩容的,而Vector则不是,Vector可以手动来设置每次扩容的大小,如果不设置的话默认则是原始大小的2倍
3、相同点
简单来说相同点都是实现了List接口,底层都是通过数组来进行实现的