栈是java中比较重要的数据结构,具备后进先出的特点,JDK提供了Stack,由于历史原因,目前Stack已经不被推荐使用了。但依然值得去分析它的源码,以便更好的理解栈的概念,也更好的知道它不再被推荐的原因。其次就是Stack源码非常简短,分析它的源码只需要花一点点的时间就可以。Stack继承自Vector,如需了解Vector,可点击Vector源码分析
继承关系
public class Stack<E> extends Vector<E>
Stack
继承自Vector
构造方法
public Stack() {
}
入栈
public E push(E item) {
//调用了父类Vector的addElement(item)
addElement(item);
return item;
}
//父类Vector的addElement(item)
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
push(E item)
调用了父类Vector
的addElement(item)
方法,说明3点
- 1.
Stack
基于Object[]实现
- 2.线程安全
- 3.扩容规则和
Vector
完全一样
弹栈
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
public synchronized void removeElementAt(int index) {
modCount++;
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
elementCount--;
elementData[elementCount] = null;
}
pop()移除栈顶元素,并返回栈顶元素。removeElementAt(int index)
是父类Vector
的方法。
- 1.线程安全
- 因为是最后一个元素,所以不需要通过
System.arraycopy()
方法左移,直接将元素数量--,并将最后一个元素置空。
- 因为是最后一个元素,所以不需要通过
获取栈顶元素
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
public synchronized E elementAt(int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
调用父类Vector
的elementAt(int index)
获取最后一个元素
总结一下
通过以上分析可以看到,Stack
继承自Vector
。然而,它们是两个不同的数据结构。历史久远,也许是当时是为了快速实现栈的数据结构调用Vector
的方法,所以继承了Vector
,也因为继承了Vector
,Stack
可以复用Vector
的大量方法 。Stack
不被推荐使用的原因应该主要有以下3点:
- 1.继承关系设计不严谨
- 2.
Vector
方法加synchronized
粒度大,性能上有一定影响 - 3.有了更好的替代方案
ArrayDeque