一、前言
站在巨人的肩膀上,本系列的Java集合框架文章参考了skywang12345——Java 集合系列,真心讲的很好,可以参考。但是不足的是,时间过于长久了,大佬的文章是基于JDK1.6.0_45,对于现在来说至少都用JDK 8.0以上了,而且JDK 6.0与JDK 8.0中集合框架的改动挺大的,所以本系列的文章是基于JDK_1.8.0_161进行说明的。
二、介绍
我们先来看看Stack的类定义,以及继承关系:
java.util.Collection<E>
-> java.util.AbstractCollection<E>
-> java.util.AbstractList<E>
-> java.util.Vector<E>
-> java.util.Stack<E>
public class Stack<E> extends Vector<E>
Stack是栈。它的特性是:先进后出(FILO, First In Last Out)。
java工具包中的Stack是继承于Vector(矢量队列)的,由于Vector是通过数组实现的,这就意味着,Stack也是通过数组实现的,而非链表。当然,我们也可以将LinkedList当作栈来使用。
再来从整体看一下Stack与Collection关系,如下图:
由于Stack和继承于Vector,因此它也包含Vector中的全部API。
三、解析
对源码的解析,我个人喜欢从方法的使用上去看,而不是把源码所有的方法从头到尾的都去看一遍,除非是那种比较短的源码还行,如果是上千行代码的话,我觉得会很崩溃的。这样不仅学习效率底下,而且看源码本身就是一件非常枯燥的事情,容易看着看着就不想看下去了(大佬忽略),非常打击学习源码的兴趣。
1、Stack类没有自己的成员变量,所以我们就直接看看它的构造方法。Stack只有1个默认的不带参数的构造方法
public Stack() {
}
2、我们知道,栈添加元素时我们称为入栈,那么就看看入栈方法。
//把元素压入栈顶
public E push(E item) {
//addElement是调用Vector中的方法,具体的相关方法就不展开详述了,可以参考上篇Vector文章
//添加元素到数组的末尾
addElement(item);
//返回元素
return item;
}
3、栈删除元素的方法我们称为出栈,看看出栈方法
//栈顶元素出栈
public synchronized E pop() {
E obj;
int len = size();
//获取栈顶元素
obj = peek();
//调用Vector中的removeElementAt,删除数组中的最后一个元素
removeElementAt(len - 1);
//返回出栈的元素
return obj;
}
//获取栈顶元素,不会执行删除操作
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
//这里也是调用Vector中的elementAt方法,根据下标索引返回元素值
return elementAt(len - 1);
}
4、Stack其他的方法。
//判断Stack是否为空
public boolean empty() {
return size() == 0;
}
//通过元素获取它最靠近栈顶的对应的索引
public synchronized int search(Object o) {
//获取数组最后匹配元素的下标(即栈底的索引)
int i = lastIndexOf(o);
if (i >= 0) {
//返回从栈顶往下的索引
return size() - i;
}
//未找到元素,则返回-1
return -1;
}
四、总结
(01)Stack实际上也是通过数组去实现的。
执行push时(即,将元素推入栈中),是通过将元素追加的数组的末尾中;
执行peek时(即,取出栈顶元素,不执行删除),是返回数组末尾的元素;
执行pop时(即,取出栈顶元素,并将该元素从栈中删除),是取出数组末尾的元素,然后将该元素从数组中删除;
(02)Stack继承于Vector,意味着Vector拥有的属性和功能,Stack都拥有。
(03)Stack也是线程安全的。