一. Stack 初识

Java 集合框架提供了一个集合Stack,它提供了stack 数据结构的功能,Java 中也提供了其他很多这样的集合,这种集合完成了某种数据结构的功能

1. stack 数据结构

栈是一种“后进先出”(LIFO)的线性数据结构,是一种特殊的线性表。

在栈中,元素的添加和删除操作只能在表的一端进行,即栈顶。元素的添加和删除遵循“后进先出”(LIFO)的原则,最后添加的元素总是最先出栈,栈对元素的访问加以限制,仅仅提供对栈顶元素的访问操作

在栈中,当栈有新元素加入时,将元素放入栈中,同时将栈顶指针top值加一,使其始终指向栈顶,当元素出栈时,栈顶top值减一,使其继续指向栈顶,直到top值为-1时,栈为空。

栈做为一种线性表,其实现方式主要有两种:数组和链表

2. stack 集合说明书

在看说明书之前,我们还是先看一下整个类的继承关系,让我们现有一个大致的轮廓

首先我们从这个上面的继承关系中,看到了stack 属于List 家族,和ArrayList 以及Vector 一样,但是需要注意的实它是继承自Vector 的,也就是说它是线程安全的

还有一点需要说明的是它是继承自Vector的,也就是说它底层是借助数组实现了Stack

/** * The Stack class represents a last-in-first-out (LIFO) stack of objects.  * Stack 类代表了一种后进先出的的stack(数据结构) * It extends class Vector with five operations that allow a vector to be treated as a stack.  * 它继承了Vector使用五种操作使得vector可以像stack一样 * The usual  push and pop operations are provided, as well as a  method to peek at the top item on the stack,  * a method to test for whether the stack is empty, and a method to search * the stack for an item and discover how far it is from the top. * 提供了常用的push和pop操作,以及一个查看栈顶元素的方法peek,一个测试栈是否为空的empty和一个查找元素并返回它距离栈顶元素的距离的方法search * When a stack is first created, it contains no items. * 当stack 被首次创建的时候,它不包含任何元素 * 

A more complete and consistent set of LIFO stack operations is provided by the {@link Deque} interface and its implementations, * {@linkdeque}接口和它的实现提供了一组更加完整和一致的后进先出堆栈操作集 * which should be used in preference to this class. For example:

   {@code Deque stack = new ArrayDeque();} * 它应该被有限使用,这里给了一个例子Deque

stack = new ArrayDeque(); * @author Jonathan Payne * @since JDK1.0 */ public class Stack extends Vector {}复制代码

3. stack 构造方法

二. Stack 的常用方法

因为 Stack 继承自 Vector 类,因此它集成了 Vector的所有方法. 关于Vector 的一切你可以看深度剖析Java集合之Vector 一篇,除了这些方法Stack 有自己特有的五个方法

1. push() 方法

我们使用push 方法向Stack添加提个元素

public class JavaStack {    static Stack animals = null;    @BeforeAll    public static void stack1() {        animals = new Stack<> ();    }    @Test    public void testPush(){        animals.push("Dog");        animals.push("Horse");        animals.push("Cat");        System.out.println("Stack: " + animals);    }}// 输出结果Stack: [Dog, Horse, Cat]复制代码

接下来我们看一下源代码

public E push(E item) {    addElement(item);    return item;}复制代码

可以看到它实际上是调用了Vector 的addElement 方法,所以上面的代码中,可以看做是依次次将 Dog Horse 和 Cat 添加到了数组中,此时整个数组里的数据是这样存储的,因为我们知道addElement是依次元素到数组的末尾的,所以Cat 在最后面

需要注意的是push 方法是有返回值的

2.pop() 方法

删除栈顶元素并返回

@Testpublic void testPop(){    animals.push("Dog");    animals.push("Horse");    animals.push("Cat");    System.out.println("Removed Before: " + animals);    String element = animals.pop();    System.out.println("Removed Element: " + element);    System.out.println("Removed After: " + animals);}复制代码

输出结果

Removed Before: [Dog, Horse, Cat]Removed Element: CatRemoved After: [Dog, Horse]复制代码

因为我们从栈的定义知道,删除操作删除的实最后添加的元素,然后我们从push 方法知道了数组中数据的存放顺序,接下来,上面的输出证明了我们的想法,我们可以看到,删除了最后添加的Cat,也就是数组中最后面的一个元素,这就是栈的特点LIFO

那么这个时候我们猜测,pop 方法实际上调用的是Vector 的removeElementAt方法,传入的参数是最后一个元素的下标,也就是数组大小减去1,接下来我们从源码验证一下我们的猜想

public synchronized E pop() {    E       obj;    int     len = size();    obj = peek();    removeElementAt(len - 1);    return obj;}复制代码
public synchronized E peek() {    int     len = size();    if (len == 0)        throw new EmptyStackException();    return elementAt(len - 1);}复制代码

其实我们看到和我们的猜想基本一致,不同的实这里为了返回要被删除的元素,先调用了elementAt方法,然后猜调用了removeElementAt 方法

这里有一个问题需要注意的是pop 是由synchronized 修饰的,其实pop 方法里面的调用的三个方法都是由synchronized 修饰的,这里你可以思考一下为什么该方法还要被synchronized修饰,其实这个就涉及到了一个问题,就是我们希望这三个方法被放在一起然后原子性执行,否则就不能保证逻辑的正确性

3.peek() 方法

返回栈顶元素

 @Test public void testPeek(){     animals.push("Dog");     animals.push("Horse");     animals.push("Cat");     System.out.println("Peek Before: " + animals);     String element = animals.peek();     System.out.println("Peek Element: " + element);     System.out.println("Peek After: " + animals); }复制代码

输出结果

Peek Before: [Dog, Horse, Cat]Peek Element: CatPeek After: [Dog, Horse, Cat]复制代码

这个代码就太简单了,然后就不解释了,但是需要注意一个问题,就是peek 方法会抛出异常,也就说你在调用的时候需要判断一下是否是空栈

public synchronized E peek() {    int     len = size();    if (len == 0)        throw new EmptyStackException();    return elementAt(len - 1);}复制代码

4.search()

search 方法可以返回特定元素以栈顶元素为基础在栈中的位置,其实就是返回这个方法在栈中的位置,然后栈中的第一个元素所在位置是1

@Testpublic void testSearch(){    animals.push("Dog");    animals.push("Horse");    animals.push("Cat");    System.out.println("Search Before: " + animals);    int position1 = animals.search("Horse");    System.out.println("Search Horse Element: " + position1);    position1 = animals.search("Dog");    System.out.println("Search Dog Element: " + position1);}复制代码

输出结果,因为Cat 的位置是1,所以我们可以看出其他的

Search Before: [Dog, Horse, Cat]Search Horse Element: 2Search Dog Element: 3复制代码

接下来我们看一下这个方法的实现

/** * Returns the 1-based position where an object is on this stack. * 返回以1 为基础的元素在stack 中的位置 * If the object o occurs as an item in this stack, this * method returns the distance from the top of the stack of the * occurrence nearest the top of the stack; the topmost item on the * stack is considered to be at distance 1. The equals * method is used to compare o to the * items in this stack. * @param   o   the desired object. * @return  the 1-based position from the top of the stack where *          the object is located; the return value -1 *          indicates that the object is not on the stack. */public synchronized int search(Object o) {    int i = lastIndexOf(o);    if (i >= 0) {        return size() - i;    }    return -1;}复制代码

本质上还是依赖数组的实现,首先找出了该元素在数组中倒数的位置距离,然后用数组大小减去了该距离

5. empty() 方法

检测栈是否为空

@Testpublic void testEmpty(){    animals.push("Dog");    animals.push("Horse");    animals.push("Cat");    System.out.println(animals.empty());    System.out.println(new Stack<>().empty());}复制代码

不为空返回false 为空返回true ,因为底层是Vector ,所以我们可以猜测这个方法的实现是依赖size 方法的,接下来我们看一下它的实现

public boolean empty() {    return size() == 0;}复制代码

三. 总结

stack 集合实现了数据结构Stack 的定义,底层依赖Vector 实现也就是数组,对栈顶元素的操作实际上是对数组尾部元素的操作,因为这样可以避免数据的迁移

push方法java_万字长文深入浅出谈Java数据类型系列之Stack相关推荐

  1. 万字长文深入理解java中的集合-附PDF下载

    文章目录 1. 前言 2. List 2.1 fail-safe fail-fast知多少 2.1.1 Fail-fast Iterator 2.1.2 Fail-fast 的原理 2.1.3 Fai ...

  2. 两万字长文读懂 Java 集合!

    作者 | 小菠萝 来源 | Java建设者(ID:javajianshe) 这篇文章历经过 5 次的打磨和修复,只为把最好的文章为大家分享. 集合在我们日常开发使用的次数数不胜数, ArrayList ...

  3. 「万字长文」谈认知差异——理解层次中的“金字塔”

    本文发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明- 当看到知乎一篇7万+赞的文章(点击阅读原文可查看),思绪万千久久回荡无法消 ...

  4. 万博java_构建高效的企业级Java应用系列(一)架构篇——1

    当开发企业级应用.规划和设计系统基本流程的时候,以下的建议可以帮助我们建立一个高性能.高扩展性的企业级系统提供的框架. 1:优先采用组件作为开发.部署和重用的核心元素 强调在J2EE应用开发中组件的概 ...

  5. Java数据类型系列之包装类

    包装类 在Java5 中添加了两个新特性,那就是自动装箱和拆箱,因为基本类型的广泛使用,但是Java 又是面向对象的语言,所以提供了包装类型的支持 我们知道基本数据类型包括byte, short, i ...

  6. Java数据类型系列之BigDecimal

    BigDecimal 这篇文章我们会介绍一下Java 中的BigDecimal,并且会通过一些例子演示它的用法,例如精度的操作 Java在java.math包中提供的API类BigDecimal,用来 ...

  7. java虚拟机类加载机制浅谈_浅谈Java虚拟机(三)之类加载机制

    在<浅谈Java虚拟机>这篇文章中,我们提到了JVM从操作系统方面来说,可以将其看做是一个进程,分别有类加载器子系统,执行引擎子系统和垃圾收集子系统.这一篇文章就简单的来谈一下类加载器子系 ...

  8. Java 集合系列 16 HashSet

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  9. 两万字长文总结,梳理 Java 入门进阶那些事

    两万字长文总结,梳理 Java 入门进阶那些事 先给大家看下完整的思维导图,也是这篇文章的主要脉络. Java从入门到进阶学习路线 主导三个项目,让我独当一面 能力提升你要怎么学 全篇总结 Java ...

最新文章

  1. Educational Codeforces Round 50 (Rated for Div. 2)的A、B、C三题AC代码
  2. TTL传输中过期的解决办法
  3. SpringMVC请求处理流程
  4. NetBeans eclipse比較
  5. SQL Server 2005参考:Apply运算符
  6. linux修改动态ip名领,Linux动态和静态修改ip(转)
  7. 阿里云镜像下载ubuntu 1
  8. python编程设计_程序设计入门—Python
  9. 【Clickhouse】Clickhouse MergeTree家族引擎
  10. C# 使用Epplus导出Excel [4]:合并指定行
  11. java继承类长方形面积_java_java用接口、多态、继承、类计算三角形和矩形周长及面积的方法,本文实例讲述了java用接口、多 - phpStudy...
  12. 0322Private strand flush not complete
  13. Yolov2 训练时anchor是如何使用的?build_target
  14. 建设智能机房--动环监控系统你不能不知道的事
  15. 星星之火-34:傅里叶分析的9大步骤
  16. Dropbox安装包官网下载失败的解决方法
  17. AddressSanitizer: heap-buffer-overflow on address 0x602000000534 at pc 0x00000040699d bp 0x7ffce0afd
  18. 谈谈ETL中的数据质量
  19. 和差角证明托勒密定理
  20. (3)riak_core系统的工作方式

热门文章

  1. 【ZZ】字符编码笔记:ASCII,Unicode和UTF-8
  2. [linux]在Linux里设置环境变量的方法(export PATH)
  3. [独库骑行之我们穿过草原]巴音布鲁克大草原
  4. 【杂项】原来有两种单引号(单引号和反引号)
  5. HDFS重复上传文件将会覆盖原文件
  6. 【收藏】比Xshel更好用的 FinalShell
  7. vue商城项目开发:浏览器自动访问、路由样式修改及定义和导入组件
  8. Java 8大原子操作
  9. JVM调优:JVM内存分代模型
  10. Linux centos查看cpu信息命令