开发者

Java中的栈概述及JVM 中的栈结构

目录
  • 一、什么是栈(Stack)
  • 二、栈的基本操作
  • 三、栈的存储结构
  • 四、栈的典型应用场景
    • 1. 函数调用与返回(Call Stack)
    • 2. 表达式求值与语法解析
    • 3. 递归与回溯(Recursion & Backtracking)
    • 4.其他算法中的应用
  • 五、栈在 JVM 中的体现
    • 1.JVM 栈的结构与作用
    • 2. 操作数栈:JVM 的“计算引擎”
    • 3. JVM 调用栈过程
  • 六、栈与 JVM 的关系对照表
    • 五、总结

      一、什么是栈(Stack)

      栈(Stack) 是一种受限的线性数据结构,只能在一端(称为 栈顶(Top))进行插入和删除操作。

      它遵循 后进先出(LIFO, Last In First Out) 的原则 —— 后放进去的元素先被取出。

      可以把它想象成“叠盘子”的场景:

      把盘子一个个叠上去 → 压栈(push)

      取盘子时只能从最上面拿 → 弹栈(pop)

      这就是栈的直观模型。

      二、栈的基本操作

      操作含义
      push(x)将元素 x 压入栈顶
      pop()移除并返回栈顶元素
      peek() / top()查看栈顶元素但不删除
      isEmpty()判断栈是否为空

      三、栈的存储结构

      栈可以通过两种方式实现:

      顺序栈(Arrawww.devze.comy Stack):

      使用数组实现,结构简单、访问高效。

      常用于空间大小可预估的情况。

      JVM 的操作数栈就是基于数组实现的。

      链栈(Linked Stack):

      使用链表实现,插入删除灵活,不需要预设大小。

      适合栈深不确定的场景(如深度递归)。

      四、栈的典型应用场景

      1. 函数调用与返回(Call Stack)

      当函数 A 调用函数 B 时:

      函数 A 的局部变量与返回地址会被压入栈;

      JVM 跳转执行函数 B;

      当 B 执行完毕后,栈顶记录被弹出,返回 A 的调用点继续执行。

      void A() {
          B();
      }
      void B() {
        android  System.out.println("Hello Stack");
      }

      执行流程:

      A() 调用 → JVM 为 A 创建栈帧 → 压栈
      A 调用 B → JVM 为 B 创建栈帧 → 压栈
      B 执行完 → B 的栈帧出栈 → 返回 A
      A 执行完 → A 的栈帧出栈

      每个方法调用都对应着 一次入栈与出栈操作。

      这就是我们常说的“调用栈”。

      2. 表达式求值与语法解析

      栈是编译器和解释器处理中缀表达式的关键结构。

      例如表达式:

      (1 + 2) * 3

      求值过程(编译器利用栈存储操作符与中间结果):

      (1)读取 ( → 压栈(表示新的子表达式)

      (2)读取 1 → 压栈(操作数)

      (3)读取 + → 压栈(操作符)

      (4)读取 2 → 压栈

      (5)遇到 ) → 弹出操作符与操作数计算(得到 3),结果压栈

      (6)读取 * → 压栈

      (7)读取 3 → 压栈

      (8)弹出 * 与两个操作数计算(得到 9)

      最终结果为 9。

      类似逻辑也用于:

      括号匹配校验(检查是否“左括号=右括号”)

      中缀转后缀(逆波兰表达式)

      编译器语法树构建

      3. 递归与回溯(Recursion & Backtracking)

      递归调用的本质,就是函数不断地入栈与出栈。

      例如计算阶乘:

      int factorial(int n) {
          if (n == 1) return 1;
          return n * factorial(n - 1);
      }

      执行 factorial(3) 的过程:

      factorial(3) → 入栈
      factorial(2) → 入栈
      factorial(1) → 入栈
      factorial(1) 返回 1 → 出栈
      factorial(2) 返回 2 * 1 = 2 → 出栈
      factorial(3) 返回 3 * 2 = 6 → 出栈

      当最内层函数执行完毕后,系统会逐层弹栈返回结果。

      这正是递归函数能“自动返回”的根本原因。

      4.其他算法中的应用

      DFS(深度优先搜索):利用栈保存待访问的节点

      括号匹配:用栈判断表达式是否合法

      浏览器前进/后退:前进与回退分别用两个栈保存历史

      撤销(Undo)操作:通过栈记录每次修改历史,支持一步步撤销

      五、栈在 JVM 中的体现

      JVM 是一台 基于栈的虚拟机

      这里的“栈”指的是 每个线程独有的 JVM 栈(Java Virtual MAChine Stack)。

      它记录了方法调用过程与执行状态,是 Java 程序运行的核心结构。

      1.JVM 栈的结构与作用

      当线程创建时,JVM 会为其分配一个独立的 JVM 栈。

      每次方法调用时,都会在这个栈中创建一个 栈帧(Stack Frame)。

      每个栈帧包含以下关键部分:

      组成部分说明
      局部变量表(Local Variables)存储方法参数与局部变量
      操作数栈(Operand Stack)临时计算区,用于执行字节码运算
      动态链接指向运行时常量池中该方法的引用
      方法返回地址方法执行完后返回调用点

      当方法被调用时:栈帧入栈

      当方法执行完毕时:栈帧出栈

      每个线程的调用链条就是 JVM 栈帧的入栈与出栈过程。

      2. 操作数栈:JVM 的&编程客栈ldquo;计算引擎”

      JVM 并不像 CPU 一样通过寄存器运算,而是依靠 操作数栈(Operand Stack) 来完成计算。

      例如:

      int a = 1;
      int b = 2;
      int c = a + b;
      

      对应字节码:

      0: iconst_1    // 将常量1压入栈
      1: istore_1    // 弹出1,存入局部变量表槽1 (a)
      2: iconst_2    // 压入常量2
      3: istore_2    // 弹出2,存入槽2 (b)
      4: iload_1     // 取出a压入操作数栈
      5: iload_2     // 取出b压入操作数栈
      6: iadd        // 弹出两个数相加,结果压栈
      7: istore_3    // 弹出结果,存入槽3 (c)
      

      所有运算都通过“压入栈 → 运算 → 弹出”完成。

      这正是 JVM 基于栈结构执行指令的直接体现。

      3. JVM 调用栈过程

      例如:

      public static void main(String[] args) {
          foo();
      }www.devze.com
      public static void foo() {
          bar();
      }
      public static void bar() {}

      执行过程:

      步骤事件栈状态(自下而上)
      main() 开始执行[main]
      main 调用 foo()[main → foo]
      foo 调用 bar()[main → foo → bar]
      bar 执行完毕[main → foo]
      foo 执行完毕[main]
      main 执行完毕[](空栈)

      可以把调用栈理解为“任务清单叠叠乐”:

      每次调用方法就是“加一张任务卡”,执行完就“拿掉最上面的那张&rdqcxjWTLuo;。

      六、栈与 JVM 的关系对照表

      内容栈的普通概念JVM 中的体现
      存储单位元素栈帧(Stack Frame)
      操作方式push / pop方法调用 → 入栈,方法返回 → 出栈
      访问原则LIFO(后进先出)方法的调用与返回顺序
      主要用途表达式计算、递归、回溯保存局部变量、执行指令、维护调用链
      结构组成栈顶、栈底局部变量表 + 操作数栈 + 链接信息

      五、总结

              栈(Stack)是一种遵循“后进先出”(LIFO)原则的线性数据结构,只能在一端进行插入和删除操作,常用来保存临时数据和控制程序执行流程。在计算机中,栈的思想贯穿编译、运行与算法设计全过程:在算法中用于递归、回溯、括号匹配、撤销操作等;在编译器中用于表达式求值和语法解析;在 JVM 中,每个线程都有独立的 JVM 栈,用来管理方法调用,通过“栈帧”的入栈与出栈保存局部变量、返回地址和计算过程,操作数栈则承担所有计算任务。可以说,栈不仅是数据结构中的重要基础,更是理解程序执行机制、方法调用过程和虚拟机底层原理的核心。

      到此这篇关于Java中的栈概述及JVM 中的栈结构的文章就介绍到这了,更多相关java jvm栈内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜