Stack源码深度解析以及应用介绍

基于JDK1.8对Java中的Stack集合的源码进行了深度解析,包括各种方法的底层实现,并且给出了Stack的使用建议。

1 Stack的概述

public class Stack< E >
extends Vector< E >

Stack,来自于JDK1.0 的古老集合类,底层是数组结构,元素可重复,有序(存放顺序),支持下标索引访问,允许null元素。

Stack类继承了Vector,所有方法的实现都是同步的,方法采用了synchronized修饰,数据安全,效率低!

Stack针对Vector扩展了五个API方法,主要被用来实现为先进后出(FILO)的栈。

2 Stack的源码解析

由于Stack继承了Vector类,因此继承了Vector类的属性和方法,同时他扩展了Vector类的方法,即新增了五个方法,用于实现先进后出的栈结构。关于Vector集合的介绍,可以看这篇文章:Java的Vector集合源码深度解析以及应用介绍

Stack的将底层数组的尾部看成了栈顶,因此入栈时将元素加在尾部,出栈时直接移除尾部的元素,比较简单,不会导致大量元素位置移动!

2.1 构造器

仅有一个自己的构造器!用于创建一个空堆栈。

public Stack() {
}

2.2 API方法

这里讲解相比于Vector新增的将用于实现栈的五个方法!

2.2.1. public E push(E item)

压栈:将新元素放在栈顶的位置。新加入的元素把原来的元素往下“压”,默认最后加入的元素在栈顶。

/**
 * 压栈(入栈),在内部实现是将元素放在内部数组的末尾
 * @param item 添加的元素
 * @return 被添加的元素
 */
public E push(E item) {
    //调用了父类的addElement方法,将元素放在内部数组的末尾
    addElement(item);
    //返回被添加的元素
    return item;
}

2.2.2 public E peek()

获得栈顶元素,但是不移除。如果栈为空,将抛出EmptyStackException异常。

/**
 * 获取栈顶元素但不移除
 * @return 栈顶元素
 */
public synchronized E peek() {
    //获取元素数量
    int     len = size();
    //如果数量等于0则说明是空栈,抛出异常
    if (len == 0)
        throw new EmptyStackException();
    //返回内部数组的尾部元素
    return elementAt(len - 1);
}

2.2.3 public E pop()

获得栈顶,并移除(弹栈)。如果栈为空,将抛出EmptyStackException异常。

/**
 * 获取栈顶元素并不移除
 * @return 栈顶元素
 */
public synchronized E pop() {
    E       obj;
    //获取元素数量
    int     len = size();
    //获取栈顶元素但不移除
    obj = peek();
    //移除底层数组尾部元素
    removeElementAt(len - 1);
    //返回被出栈的元素
    return obj;
}

2.2.4 public boolean empty()

判断栈容器是否为空栈。

public boolean empty() {
    //很简单,直接看元素数量是否等于0
    return size() == 0;
}

2.2.5 public int search(Object o)

搜索o在栈空间当中的位置:以1为基础,从栈顶开始计算,返回值为-1时表示此对象不在堆栈中。底层使用 equals 方法比较 o 与堆栈中的项。

/**
 * 搜索o在栈空间当中的位置:以1为基础,从栈顶开始计算,返回值为-1时表示此对象不在堆栈中。底层使用 equals 方法比较 o 与堆栈中的项。
 * @param o 搜索的元素
 * @return 位置
 */
public synchronized int search(Object o) {
    //从尾部倒序向头部搜索索引位置,返回第一个被找到的元素的索引,没找到返回-1
    int i = lastIndexOf(o);
    //如果位置i大于等于0,则返回size-i;
    //即如果size=5,i=4,那么该元素在"栈"结构中的位置因该是1,即以1为基础,栈顶元素位置就是1
    if (i >= 0) {
        return size() - i;
    }
    //没找到就返回-1
    return -1;
}

2.2.6 案例

public class StackDemo01 {

    public static void main(String[] args) {
        Stack<String> s = new Stack<>();
        s.push("a");
        s.push("b");
        s.push("c");
        s.push("d");
        while (!s.empty()) {
            String pop = s.pop();
            System.out.print(pop + " ");
        }
    }
}

3 总结

Stack类的实现还是很简单的,相比父类Vector就是多了五个方法。但是由于来自于JDK1.0,那时候的集合都很原始并且使用Synchronized修饰,性能可能不是很好,并且底层实现比较粗糙!

在JDK1.6的时候,添加了集合类ArrayDeque,该类实现了Deque接口,即作为一个“双端队列”,可以被用来实现Stack(栈)或者Queue(队列)。

ArrayDeque内部是采用可变数组实现的双端队列,采用两个外部引用来保持队列头结点和尾节点的访问,同时删除队列头尾元素时不会移动其他元素,而是移动引用的位置,即形成一个环形队列,能够复用数组空间(允许队头索引比队尾索引值更大),相比于另外一个使用链表实现的双端队列LinkedList综合效率更好(LinkedList介绍:Java的LinkedList集合源码深度解析以及应用介绍)!同时,如果用于实现栈,那么相比于Stack的综合效率同样更好!不过ArrayDeque不支持null元素,并且不是线程安全的!

因此,JDK推荐我们一般使用ArrayDeque来替代Stack实现栈!

同时如果你真的想了解JVM的栈空间的工作过程,可以看看这篇文章:Java的JVM运行时栈结构和方法调用详解,看完你会发现为什么上面的集合可以用来模拟“栈空间”了,因为方法在栈空间中的调用也是“先进后出”的!

我们后续将会介绍的更多集合,比如TreeMap、HashMap,LinkedHashMap、HashSet、TreeSet、ArrayDeque等基本集合以及JUC包中的高级并发集合。如果想学习集合源码的关注我的专栏更新!

如果有什么不懂或者需要交流,可以留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值