概述
在前两章我们已经学习了List常用的两个实现ArrayList
、LinkedList
,下面我们来学习下Vector
.Vector
和ArrayList
一样是基于数组实现的List,区别在于Vector是线程安全的,我们来研究下其源码.Vector和ArrayList配合食用,味道更佳哦...
源码分析
结构图
继承关系
public class Vector
extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable{}
Vector
和ArrayList
一样实现了List
接口,继承了AbstractList
类.
类中属性
/** 和ArrayList一样,这个是核心数组 */
protected Object[] elementData;
/** 元素数量(Vector的实际容量) */
protected int elementCount;
/** 扩容因子 */
protected int capacityIncrement;
/** 版本号 */
private static final long serialVersionUID = -2767605614048989439L;
/** AbstractList里的属性, 记录集合 涉及到结构变化的次数(add/remove/clear等) */
protected transient int modCount = 0;
类中的属性也和ArrayList
相差不多,内部维护Object[]
数组来存储元素,和ArrayList
唯一的区别是多了个capacityIncrement
变量.至于这个变量是干什么的,咱们继续往下看.
构造函数
Vector
有四个构造器
/** 初始化容量, 设置扩容因子 */
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(int initialCapacity) {
this(initialCapacity, 0);
}
/** 无参构造器 设置初始容量10 */
public Vector() {
this(10);
}
/** 创建包含指定集合 */
public Vector(Collection extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
几个构造函数区别不大,都是进行初始化容量,数据和扩容因子capacityIncrement
.
核心函数
由于接口实现较多,各个功能的多个实现核心差不多,这里挑选每种功能里核心的来讲解.如想深入每个函数,请自行
翻阅源码.
添加函数
/** 在指定下标位置上插入元素 */
public synchronized void insertElementAt(E obj, int index);
/** 插入一个元素 */
public synchronized void addElement(E obj);
/** 添加一个元素 */
public synchronized boolean add(E e);
/** 在指定位置上插入一个元素 */
public void add(int index, E element);
/** 将指定的元素集从index下标开始插入到Vector中 */
public synchronized boolean addAll(int index, Collection extends E> c);
synchronized void addElement(E obj)
/** 插入一个元素 */
public synchronized void addElement(E obj) {
modCount++;
// 触发扩容
ensureCapacityHelper(elementCount + 1);
// 赋值
elementData[elementCount++] = obj;
}
addElement(E obj)
代码比较简单,触发扩容,然后赋值.再来看看扩容代码
/** 扩容的中间调用 */
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
// 扩容核心方法
grow(minCapacity);
}
/** Vector 扩容的实际方法 */
private void grow(int minCapacity) {
// 大小
int oldCapacity = elementData.length;
// 如果 capacityIncrement 大于0,则每次递增 capacityIncrement 个,
// 否则 容量翻倍.
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
// 如果新设的容量小于 minCapacity(最小容量限制),则新设容量等于 minCapacity
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;
}
实际上扩容的代码和ArrayList
也是差不多的, 唯一的区别体现于扩容容量.ArrayList
每次扩容为其原本容量的0.5倍,而Vector
则是根据扩容因子capacityIncrement
来计算每次容量的增长,如果capacityIncrement
小于0,每次扩容为原本容量的一倍.若大于0,每次容量增加capacityIncrement
个.
synchronized void insertElementAt(E obj, int index)
/** 在指定下标位置上插入元素 */
public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
// 触发扩容
ensureCapacityHelper(elementCount + 1);
// 往后挪
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
// 赋值
elementData[index] = obj;
elementCount++;
}
synchronized boolean addAll(int index, Collection extends E> c)
/** 把指定的集合的所有元素添加到Vector中 */
public synchronized boolean addAll(Collection extends E> c) {
modCount++;
Object[] a = c.toArray();
int numNew = a.length;
// 扩容
ensureCapacityHelper(elementCount + numNew);
// 进行copy
System.arraycopy(a, 0, elementData, elementCount, numNew);
// 设置新的元素数量
elementCount += numNew;
return numNew != 0;
}
获取函数
/** 获取元素 */
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
/** 返回数组指定下标的元素 */
E elementData(int index) {
return (E) elementData[index];
}
修改函数
/**
* 给指定位置设置新元素,并且返回旧元素
*/
public synchronized E set(int index, E element) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 获取旧的元素
E oldValue = elementData(index);
// 重新赋值
elementData[index] = element;
return oldValue;
}
删除函数
/**
* 根据下标删除一个元素,并返回此元素
*
* 实现逻辑和ArrayList的类似
*/
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)
// 把index+1后的所有元素拷贝一份从index位置开始
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 同时删除最后一个多余的元素(拷贝后导致的最后一个元素的重复出现(最后一个和倒数第二个元素是重复的))
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
Vector
里的函数和ArrayList基本上类似,没什么需要特别讲的.注意Vector
供外部访问的函数均被synchronized
关键字所修饰属于线程安全的.
和ArrayList对比
- Vector是线程安全的,而ArrayList不是,从源码可以看出Vector中很多函数被synchronized修饰,虽然这赋予了Vector的线程安全的特性,但也导致Vector在效率上无法和ArrayList相比.
- Vector和ArrayList采用的都是数组存储,当空间不足进行扩容时,ArrayList每次扩容是原容量的0.5倍,而Vecotr则是自定义每次扩容的增长量,默认为1倍.
注意
现在官方已经不推荐使用Vector了,Vector被认为是Java中的遗留类.
Vector在JDK1.0中首次引入,后来经过改进又实现了List接口,尽管它现在已经是集合大家庭的一员,但它很少在新项目中被使用,仅处于向后兼容而受支持.
根据Vector的java文档,如果不需要使用线程安全的实现,建议使用ArrayList代替Vector.
如果需要使用线程安全的集合,则可以使用CopyOnWriteArrayList,也可以使用Collections.synchronizedList()通过外部方式把ArrayList变为线程安全的(仅限于原子操作).