Java程序的生命周期主要分为5个阶段
1. 第一阶段:Java 源代码 Sample.java
- 内容:人类可读的 Java 代码,我们日常编写的类、方法、变量都写在这里,后缀
.java。
2. 第二阶段:Java 编译器 javac 编译
- 工具:
javac(JDK 自带编译命令) - 作用:把人类可读的 Java 源码 ,编译成平台无关的字节码文件。
3. 第三阶段:字节码 Sample.class
编译后生成 .class 文件,图中标注 3 个关键特性:
- Non-human Readable 人类不可读:二进制文件,打开是乱码,不能直接修改;
- Machine Independent 平台无关(Java 跨平台核心) 一份
.class文件,Windows、Mac、Linux 只要安装对应系统的 JVM 就能运行,一次编译到处运行。 - 本质:一套统一的、给 JVM 识别的中间指令,不是操作系统原生机器码。
4. 第四阶段:JVM Java 虚拟机 解释 / 即时编译
JVM 是运行.class的载体,不同操作系统有专属版本的 JVM:
- JVM 接收字节码后,做两件事:解释执行 + JIT 即时编译优化
- 把统一的字节码,翻译成当前操作系统 CPU 能识别的原生二进制机器指令
5. 第五阶段:CPU 执行机器码
- 最终产物:0/1 组成的二进制机器指令,交由电脑 CPU 直接执行,完成程序逻辑。
生命周期总结
- Java源码 →javac静态编译→ 字节码class →JVM动态翻译→ CPU机器码
关键点
字节码不是二进制 ❌
字节码 (.class)、机器码全都是二进制文件 ,本质全是 0 和 1,只是解读主体、指令标准完全不同:
.class字节码:给JVM 虚拟机读的二进制指令;- 机器码:给当前操作系统 CPU读的二进制指令;
字节码 ByteCode(.class 文件)关键特性
-
统一标准,跨平台 一份
Sample.class,复制到 Windows、Mac、Linux,只要装了对应系统的 JVM 就能跑。原因:字节码指令只定义 "抽象操作"(比如加载变量、调用方法、创建对象),不绑定任何 CPU 硬件。 -
解读主体:只能被 JVM 识别,CPU 看不懂字节码
-
查看方式:不能直接记事本读,要用命令
javap -c Sample翻译成人类可读的助记符(比如aload_0、invokevirtual)。
机器码 Machine Code 关键特性
-
完全不跨平台Windows x86 的机器码,放到 Mac M 系列 ARM CPU 上直接无法识别、报错;
-
解读主体:CPU 直接执行,不需要中间层;
-
来源:由当前系统的 JVM 实时转换而来(两种方式)
- 解释执行:JVM 逐条把字节码翻译成机器码,执行完丢弃;
- JIT 即时编译:高频代码一次性编译成本地机器码缓存,提升速度(Java 性能核心优化)。
不同点
| 对比维度 | 字节码 .class | 机器码 |
|---|---|---|
| 阅读对象 | JVM 虚拟机 | 电脑 CPU |
| 平台属性 | 跨全平台,一次编译到处运行 | 绑定系统 + CPU,无法跨平台 |
| 生成时机 | 开发阶段:javac 提前静态编译 |
运行阶段:JVM 实时动态转换生成 |
| 指令作用 | 抽象逻辑(创建对象、调用方法) | 硬件底层操作(寄存器读写、内存寻址) |
前端专属通俗举例帮你吃透
把 JVM 想象成浏览器:
- Java 源码 = TS 代码
- 字节码 = TS 编译后的统一中间字节码(所有浏览器通用)
- 机器码 = 浏览器 V8 把中间字节码,转成你电脑 CPU 专属指令
总结
- Java 跨平台靠的是字节码 + 多系统适配的 JVM,不是机器码;
- 字节码、机器码都是二进制,区别只是 "给谁看";
- 编译分两段:开发期静态编译出字节码,运行期 JVM 动态转机器码。