Vector是线程安全的ArrayList,自JDK1.0开始就有了,而ArrayList是在JDK1.2才开始有的.Vector的也是基于动态数组的,实现逻辑与ArrayList几乎一模一样,主要区别在与增删改查方法上增加了synchronized关键字,用来保障多线程安全.Stack是Vector的唯一子类,用来实现栈操作push/pop,它本质上也是基于数组实现的。
下面是Vector的结构图:
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;
private static final long serialVersionUID = -2767605614048989439L;
private static final int MAX_ARRAY_SIZE = 2147483639;
public Vector(int var1, int var2) {
if(var1 < 0) {
throw new IllegalArgumentException("Illegal Capacity: " + var1);
} else {
this.elementData = new Object[var1];
this.capacityIncrement = var2;
}
}
public Vector(int var1) {
this(var1, 0);
}
public Vector() {
this(10);
}
public Vector(Collection<? extends E> var1) {
this.elementData = var1.toArray();
this.elementCount = this.elementData.length;
if(this.elementData.getClass() != Object[].class) {
this.elementData = Arrays.copyOf(this.elementData, this.elementCount, Object[].class);
}
}
上面的vector同样继承于AbstractList,实现了RandomAccess,Cloneable,Serializable这三个标记接口,默认情况下初始容量也是10,不同于ArrayList的在于多了一个capacityIncrement变量,可以用来指定扩容时容量的增长空间,下面有用到。
Vector中的add操作
public synchronized void addElement(E var1) {
++this.modCount;
this.ensureCapacityHelper(this.elementCount + 1);
this.elementData[this.elementCount++] = var1;
}
多了个synchronized修饰符,确保同步安全,调用了this.ensureCapacityHelper确保容量空间是足够的,这里的elementCount相当于ArrayList中的size(可能后来设计ArrayList的时候觉得size比较形象就替换名称了吧)。
private void ensureCapacityHelper(int var1) {
if(var1 - this.elementData.length > 0) {
this.grow(var1);
}
}
private void grow(int var1) {
int var2 = this.elementData.length;
int var3 = var2 + (this.capacityIncrement > 0?this.capacityIncrement:var2);
if(var3 - var1 < 0) {
var3 = var1;
}
if(var3 - 2147483639 > 0) {
var3 = hugeCapacity(var1);
}
this.elementData = Arrays.copyOf(this.elementData, var3);
}
上面的实现与ArrayList一样没什么好说的,区别在于这里如果指定的扩充容量>0,这时扩充的容量是当前数组的容量加上capacityIncrement之和的总量,否则就是把当前容量扩大至当前数组容量的两倍,如果扩容后仍然小于需要的容量,就把当前的容量大小设置为需要的容量,最后复制数组到设定的总容量数组中。
其他的remove,get等方法与Arraylist的实现基本一致,这里不再赘述。
Stack继承与Vector它实现了栈操作,先进后出的思想实现。
public class Stack<E> extends Vector<E> {
private static final long serialVersionUID = 1224463164541339165L;
public Stack() {
}
public E push(E var1) {
this.addElement(var1);调用的 Vector.addElement(),添加到尾部
return var1;
}
public synchronized E pop() {
int var2 = this.size();
Object var1 = this.peek();调用peek()获取最后一个数据,最后返回
this.removeElementAt(var2 - 1);删除最后一个数据元素
return var1;
}
public synchronized E peek() {获取Vector中最后一个数据,但不删除
int var1 = this.size();
if(var1 == 0) {
throw new EmptyStackException();
} else {
return this.elementAt(var1 - 1);
}
}
public boolean empty() {
return this.size() == 0;
}
public synchronized int search(Object var1) {
int var2 = this.lastIndexOf(var1);
return var2 >= 0?this.size() - var2:-1;
}
}
上面的源码实现比较简单,上面出现个序列化版本号,这里简单提下Seriliable是具备继承性的.
完成入栈/出栈操作的思想是:push的时候把数据元素添加到集合尾部,pop的时候获取集合尾部数据并删除,这样就实现了基于动态数组先进后出的逻辑实现。因为LinkList实现了双端队列Deque所以使用LinkList也可以很轻松的完成栈和队列的实现。详情见java集合之LinkList解析
上面的方法除了push没有加synchronized,pop/peek/search都加了synchronized,实现同步操作.
如果没有线程安全的需求,一般推荐使用 ArrayList,而不是 Vector,因为每次都要频繁的获取/释放锁操作,效率比较低。