Java集合框架-Stack的源码解析

630 阅读3分钟

一、前言

站在巨人的肩膀上,本系列的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也是线程安全的。

五、参考

Java 集合系列07之 Stack详细介绍(源码解析)和使用示例