Vector
,一个可变长的数组,底层实现与ArrayList 大同小异,但 Vector
是同步的(线程安全), Vector
的很多方法之前都加了关键字 synchronized
,所以是线程安全的。
由于Vector的实现和ArrayList的实现大同小异,这里就不再逐一分析Vector中的方法,主要分析一下和ArrayList不同的方法。
首先我们还是来看以下Vector中定义的变量
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
protected Object[] elementData; // 存储Vector中元素
protected int elementCount; // Vector中的元素个数
protected int capacityIncrement; // Vector的增长系数
private static final long serialVersionUID = -2767605614048989439L; // Vector的序列版本号
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 能够分配元素数量的最大值
}
Vector
有四个构造方法,其内部有两个重要的参数,一个是 elementCount
代表当前元素个数,一个是 capacityIncrement
代表当列表元素满了之后增加的容量。如果不设置 capacityIncrement
,那么 Vector
容量扩展时默认将扩展两倍,在ArrayList源码分析中,我们可以知道 ArrayList
在扩容时默认将扩展1.5倍。
ector
初始时容量为 10
,而 ArrayList
初始容量为 0
。
// Vector构造函数。默认容量是10。
public Vector() {
this(10);
}
// 指定Vector容量大小的构造函数
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
// 指定Vector"容量大小"和"增长系数"的构造函数
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
// 新建一个数组,数组容量是initialCapacity
this.elementData = new Object[initialCapacity];
// 设置容量增长系数
this.capacityIncrement = capacityIncrement;
}
// 指定集合的Vector构造函数。
public Vector(Collection<? extends E> c) {
// 获取“集合(c)”的数组,并将其赋值给elementData
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);
}
Vector
中的构造器和 ArrayList
中的基本相同,只不过 Vector
中多了一个可以自定义增长系数的构造器 public Vector(int initialCapacity, int capacityIncrement)
Vector
中的添加元素和 ArrayList
中的大同小异,这里不再具体分析,这里只分析下Vector的扩容机制
/**
* 增加vector容量
* 如果vector当前容量小于至少需要的容量,它的容量将增加。
* 新的容量将在旧的容量的基础上加上capacityIncrement,除非capacityIncrement小于等于0,在这种情况下,容量将会增加一倍。
* 增加后,如果新的容量还是小于至少需要的容量,那就将容量扩容至至少需要的容量。
*/
public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity > 0) {
modCount++;
ensureCapacityHelper(minCapacity);
}
}
/**
* ensureCapacity()方法的unsynchronized实现。
* ensureCapacity()是同步的,它可以调用本方法来扩容,而不用承受同步带来的消耗
*/
private void ensureCapacityHelper(int minCapacity) {
// 如果至少需要的容量 > 数组缓冲区当前的长度,就进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 分派给arrays的最大容量
* 为什么要减去8呢?
* 因为某些VM会在数组中保留一些头字,尝试分配这个最大存储容量,可能会导致array容量大于VM的limit,最终导致OutOfMemoryError。
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 扩容,保证vector至少能存储minCapacity个元素。
* 首次扩容时,newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);即如果capacityIncrement>0,就加capacityIncrement,如果不是就增加一倍。
* 如果第一次扩容后,容量还是小于minCapacity,就直接将容量增为minCapacity。
*/
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();
//如果想要的容量大于MAX_ARRAY_SIZE,则分配Integer.MAX_VALUE,否则分配MAX_ARRAY_SIZE
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
Vector
中添加一个枚举方法
// 返回一个枚举类型的对象
public Enumeration<E> elements() {
return new Enumeration<E>() {
int count = 0;
public boolean hasMoreElements() { // 判断后面是否还有数据
return count < elementCount;
}
public E nextElement() { // 返回一个数据
synchronized (Vector.this) {
if (count < elementCount) {
return elementData(count++);
}
}
throw new NoSuchElementException("Vector Enumeration");
}
};
}
其他类同方法请参考ArrayList源码分析
Vector
与 ArrayList
的最大区别就是 Vector
是线程安全的,而 ArrayList
不是线程安全的。另外区别还有:
ArrayList
不可以设置扩展的容量,默认 1.5
倍; Vector
可以设置扩展的容量,如果没有设置,默认 2
倍
ArrayList
的无参构造方法中初始容量为 0
,而 Vector
的无参构造方法中初始容量为 10
。
下面我们再来分析下Vector的子类Stack方法。
Stack类代表最先进先出(LIFO)堆栈的对象。 它扩展了Vector五个操作,允许一个vector被视为堆栈。
五个方法分别是:
push() 添加元素到堆栈的顶部
pop() 删除堆栈顶部元素
peek() 查看堆栈顶部元素
empty() 判断堆栈是否为空
search() 返回元素所在位置
package java.util;
public
class Stack<E> extends Vector<E> {
/**
* Creates an empty Stack.
*/
public Stack() {
}
public E push(E item) {
addElement(item);
// 调用vector中的方法在栈顶添加一个元素
return item;
}
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
// 调用vector中的方法删除栈顶的元素
return obj;
}
public synchronized E peek() {
int len = size();
// 返回栈顶元素
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
public boolean empty() {
return size() == 0;
}
public synchronized int search(Object o) {
int i = lastIndexOf(o);
// 因为LIFO 所以选择从后往前遍历
if (i >= 0) {
return size() - i;
}
return -1;
}
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = 1224463164541339165L;
}