当前位置: 首页 > news >正文

Java 底层思考系列:从 JVM 栈帧开始,我真正理解了Java 为什么设计抽象类

从 JVM 栈帧开始,我真正理解了Java 为什么设计抽象类

关键词:JVM、Stack Frame、动态链接、抽象类、多态、方法调用、Java底层原理

最近背 Java 八股时,看到了 JVM 的栈帧(Stack Frame)

起初觉得这只是 JVM 的一个知识点:

  • 局部变量表
  • 操作数栈
  • 动态链接
  • 返回地址

后来越想越觉得:

这些东西竟然和 Java 的面向对象设计全部串起来了。

尤其是:

为什么 Java 要设计抽象类?

以前我的回答一直都是:

“为了规范子类。”

今天终于理解:

真正的原因,要从 JVM 如何调用一个方法开始。


一、一个方法调用,到底发生了什么?

例如:

publicstaticvoidmain(String[]args){Animalanimal=newDog();animal.eat();}

以前:

我脑子里的理解只有:

调用 eat() ↓ 输出结果

现在:

真正发生的是:

Java代码 ↓ 编译成 .class ↓ JVM加载类 ↓ 调用方法 ↓ 创建栈帧(Stack Frame) ↓ 执行字节码 ↓ 方法结束 ↓ 栈帧销毁

也就是说:

每调用一个方法,JVM 都会创建一个新的栈帧。

方法结束以后:

栈帧立即弹出。


二、栈帧里面到底有什么?

一个栈帧主要包含四部分。

Stack Frame ├── 局部变量表(Local Variable Table) ├── 操作数栈(Operand Stack) ├── 动态链接(Dynamic Linking) └── 返回地址(Return Address)

① 局部变量表

负责保存局部变量。

例如:

publicstaticintadd(inta,intb){intc=a+b;returnc;}

那么:

局部变量表 a b c

全部保存在这里。


② 操作数栈

负责计算。

例如:

intc=a+b;

JVM 实际会执行:

push a push b ↓ + ↓ 结果压回栈

所以:

所有:

+ - * / %

都依赖操作数栈。


③ 动态链接(Dynamic Linking)

这里看着唬人,其实就一句话秒了:

帮助 JVM 找到真正要执行的方法。

什么意思?

例如:

Animalanimal=newDog();animal.eat();

变量类型:

Animal

对象类型:

Dog

JVM 怎么知道:

应该执行:

Animal.eat()

还是:

Dog.eat()

答案就是:

动态链接。

运行期间:

JVM 根据对象真正的类型:

找到:

Dog.eat()

然后执行。

这一瞬间,

我突然意识到:

这就是多态工作的底层基础。


④ 返回地址

方法执行结束以后,

CPU 怎么知道回哪里?

例如:

main(){add();System.out.println("结束");}

add()

执行完成以后:

并不是程序结束。

而是:

继续执行:

System.out.println("结束");

所以:

栈帧里面还保存着:

返回地址。


三、动态链接,让我重新理解了多态

以前:

觉得多态只是:

Animalanimal=newDog();

今天终于知道:

真正发生的是:

animal.eat() ↓ JVM ↓ 动态链接 ↓ Dog.eat()

这也是:

为什么:

Java 可以:

父类引用 ↓ 子类对象 ↓ 调用子类方法

四、然后我突然想到一个问题

既然:

JVM 会找到真正的方法。

那:

为什么 Java 还需要抽象类?

例如:

classShape{publicdoublearea(){return0;}}

这个:

真的合理吗?

圆形:

怎么算面积?

矩形:

怎么算面积?

三角形:

怎么算面积?

父类其实根本不知道。

如果:

写一个:

return0;

只是:

为了让代码能够编译。

那这个方法:

其实毫无意义。


五、这就是抽象类存在的意义

于是:

Java 提供了:

abstractclassShape{publicabstractdoublearea();}

这里:

父类直接告诉所有子类:

我不知道怎么实现。

但是:

你必须实现。

于是:

classCircleextendsShape{@Overridepublicdoublearea(){returnMath.PI*r*r;}}

如果:

子类没有实现:

编译直接失败。

这就是:

抽象类真正解决的问题。

它不是:

帮助 JVM。

而是:

帮助程序员。


六、我曾经有一个错误理解

刚开始学习的时候,

我甚至认为:

抽象类是不是为了节省 JVM 内存?

后来查阅 JVM 规范以后,

发现这是错误的。

原因很简单。

抽象方法:

依然存在。

例如:

abstractvoideat();

JVM 依然知道:

方法名 参数 返回值 访问权限

只是:

没有方法体(Code Attribute)。

所以:

抽象类几乎不是为了节省内存。

真正的价值是:

表达设计意图。

它告诉所有开发者:

这个行为一定存在。 但是: 父类不知道如何实现。 必须交给子类。

这是:

面向对象设计。

而不是:

JVM 内存优化。


七、整个知识终于串起来了

以前:

这些知识:

在我脑子里都是独立的。

JVM 抽象类 继承 多态 Override

今天终于变成了一张图。

Java代码 ↓ 编译成字节码 ↓ JVM加载类 ↓ 方法调用 ↓ 创建栈帧 ↓ 动态链接 ↓ 找到真正的方法 ↓ 为什么需要真正的方法? ↓ 因为存在 Override ↓ 为什么允许 Override? ↓ 因为存在继承 ↓ 为什么父类没有实现? ↓ 因为父类无法提供通用实现 ↓ 于是: 抽象类诞生

这一刻:

JVM 和 Java 面向对象设计,

终于连接到了一起。


八、总结

以前学习 Java:

总是在背:

  • 什么是继承
  • 什么是多态
  • 什么是抽象类

今天第一次站在 JVM 的角度去理解:

发现这些设计,

并不是孤立存在的。

动态链接让 JVM 能够在运行时找到真正的方法。

方法重写让不同子类拥有不同实现。

抽象类则告诉编译器:

父类不知道怎么做,

所以必须由子类完成。

原来,

Java 面向对象的设计,

并不是为了炫技。

而是为了让程序的结构更加合理,让错误尽可能提前暴露,让扩展变得更加自然。


真正的学习,不是记住一个知识点,而是把一个知识点和整个知识体系连接起来。

如果一门语言的每一个设计都能回答 “为什么”,那你离真正理解它就更近了一步。

http://www.jsqmd.com/news/1147025/

相关文章:

  • AI编程系列之1:AI 编程的三种范式——从 Copilot 到 Agent 到 Spec
  • EM3080-W条码解码芯片与PIC18F57Q43系统设计实战
  • 基于STM32与TPA3128D2的高保真数字音频系统设计
  • 5步搭建Sunshine游戏串流服务器:在家打造专属云游戏平台
  • TB6593FNG与PIC32MZ的直流电机PID控制方案
  • 零基础转行Agent开发?收藏这份学习路线,小白也能轻松入门大模型!
  • TLA2518与dsPIC30F4011实现高精度ADC信号链设计
  • CAD中的捕捉控制是什么功能?CAD新手入门教程
  • 狠狠吐槽一下SSR/Next.js(二):服务端和客户端代码缠在一起,剪不断,理还乱。
  • HarmonyOS 7小艺Agent有多强?一句话帮你搞定10件事
  • 户外视觉语言导航的语义韧性设计:应对山野语义中断的四层架构
  • 一体成型电感广东专业供应商排名
  • 物流企业物流调度和单据处理优化用哪款Agent?主流方案深度测评与工程化选型指南
  • 采用 mem0 之前,先决定 Agent 到底允许记住什么
  • 短时过零率与自相关函数:2种方法在语音端点检测(VAD)中的实战对比与性能分析
  • 2026 最新 AI 学习路线全景图:从零基础到 AI 全栈测试与开发实战(附一站式智能测试平台)
  • MediaPipe TouchDesigner插件实战:3种虚拟摄像头集成方案全解析
  • 华硕 ProArt KD300 键盘评测:优缺点并存,适合多设备连接用户
  • OpenClaw部署实战:AI技能编排中枢的零基础落地指南
  • WebLogic Server 12.2.1.4 漏洞防御:5项临时缓解措施与补丁部署验证
  • 视频分析网络穿透性能优化指南
  • 【JAVA毕设源码分享】基于SpringBoot+vue的高校学生实习综合服务平台设计与实现(程序+文档+代码讲解+一条龙定制)
  • ES4X:让 JavaScript 在 Vert.x 上跑得更快
  • 跨国收购后需要全球实体合规整合,有哪些机构推荐?
  • STM32L031C6与L9958电机驱动方案设计与优化
  • 英雄联盟智能助手Seraphine:如何通过实时数据分析和自动化BP提升你的游戏胜率
  • I Doc View <13.10.1_20231115 5个高危漏洞原理与修复方案深度解析
  • 终极DLSS版本管理指南:免费工具一键提升显卡性能
  • MAX77654与PIC32MX电源管理方案设计指南
  • STM32L011K4与CMT-8540S-SMT蜂鸣器的低成本声音交互方案