Java Fundamentals
编译器负责“翻译”,虚拟机负责“执行”。从 javac 到 JVM,看一段 Java 代码如何跑起来。
.java → .classBytecode.class → 机器码纵向滚动 · 悬停可查看详情
Step by Step
悬停每个环节,看看它在这一步做了什么。
悬停任意环节即可浮现详情,移开后自动收起。
Division of Labor
从两个角色各自的视角看一遍,再悬停行查看协作关系。
在程序运行之前工作,只做一次:输入 Hello.java,检查语法与类型错误,输出与操作系统无关的 Hello.class 字节码。它不关心你最终在哪个平台上运行。
在程序运行时工作:加载 Hello.class,用类加载器验证字节码并解释执行;发现热点代码时,由 JIT 编译器直接编译成机器码并缓存,同时负责内存管理与垃圾回收。
javac 负责“统一”,JVM 负责“落地”:javac 生成平台无关的字节码,各平台安装各自的 JVM 来解读同一份字节码,因此代码只需编译一次,就能在 Windows、macOS、Linux 上运行。
Why Two Stages
如果编译器直接生成机器码,同一份代码在 Windows、macOS、Linux 上就要分别编译三次。Java 选择了中间路线:
javac 把源码编译成统一的“中间语言”——字节码,它不针对任何特定系统;JVM 在运行时把字节码解释或编译成当前系统的机器码。代码只需编译一次,就可以在任何安装了 JVM 的平台上运行。
| 编译器 javac | 虚拟机 JVM | |
|---|---|---|
| 阶段 | 编译期(编写代码后) | 运行期(执行程序时) |
| 输入 | Java 源代码 .java | 字节码文件 .class |
| 输出 | 字节码 .class | 平台相关的机器指令 |
| 职责 | 语法检查、类型检查、代码优化 | 加载类、管理内存、执行字节码 |
| 跨平台 | 只生成一次字节码,与操作系统无关 | 每个平台装不同的 JVM,运行同一份字节码 |