JVM通过“加载→验证→准备→解析→初始化”五阶段机制将.class字节码转化为可执行运行时结构:加载阶段由类加载器读取字节流、在元空间生成运行时数据、堆中创建Class对象;验证确保字节码安全合规;准备为static变量分配内存并设默认值;解析将符号引用转为直接引用;初始化执行static赋值和静态代码块,仅首次主动使用时触发。

JVM 不是直接“运行”字节码文件,而是通过一套分阶段、按需触发的类加载机制,把 .class 文件逐步转化为可执行的运行时结构。整个过程核心在于“加载→验证→准备→解析→初始化”,其中加载只是第一步,但最关键——它决定了字节码能否进入 JVM 内存。
类加载器负责把字节码“搬进”内存
类加载器(ClassLoader)是实际执行读取动作的组件。它不关心字节码从哪来:可能是本地磁盘上的 HelloWorld.class,也可能是 JAR 包里的某个类,甚至是从网络或数据库动态获取的二进制流。只要能拿到符合规范的字节流(开头必须是 CA FE BA BE 魔数),它就尝试加载。
- 加载过程包含三件事:读取字节流 → 在方法区(JDK 8+ 是元空间)生成运行时数据结构 → 在堆中创建一个
java.lang.Class对象作为访问入口 - JVM 默认使用三层类加载器协作:启动类加载器(加载
java.lang.*等核心类)、扩展类加载器(加载lib/ext下的类)、应用类加载器(加载CLASSPATH中的用户类) - 它们采用双亲委派模型:子加载器先委托父加载器尝试加载,只有父加载器无法处理时才自己动手,防止核心类被重复或恶意替换
字节码不是直接执行,而是经过五步转化
加载完成不等于就能运行。JVM 还要对字节码做安全与结构检查,并建立运行所需的内存布局和引用关系:
- 验证:检查魔数、版本号、常量池格式、字节码逻辑是否合规,防止恶意或损坏的 class 文件危害 JVM
-
准备:为类变量(
static字段)在方法区分配内存,并设默认值(如int设为 0,引用类型设为null) - 解析:把常量池里的符号引用(比如类名、方法名字符串)替换成直接引用(比如内存地址或偏移量),让调用能真正定位到目标
-
初始化:真正执行
static变量赋值语句和静态代码块——这是类加载的最后一步,也是唯一会执行 Java 代码的阶段,仅在首次主动使用时触发(如 new 实例、调用 static 方法、反射访问等)
执行引擎最终把字节码变成 CPU 指令
当类完成初始化,它的方法就可以被调用了。此时 JVM 的执行引擎登场:
- 执行引擎不直接运行字节码,而是通过解释器逐条翻译成机器指令执行;热点代码则由 JIT 编译器编译为本地机器码,提升性能
- 执行起点通常是
main()方法——JVM 启动时会主动初始化包含该方法的主类,触发整个加载链路 - 类加载是“按需”的:没用到的类不会被加载,节省内存;同一个类只会被一个类加载器加载一次,
Class对象在 JVM 中唯一
整个流程从 javac 编译出 .class 开始,到类加载完成、执行引擎启动为止,是一套严谨又灵活的机制。它既保障了安全性(验证、双亲委派),又支撑了动态性(热部署、SPI、自定义加载器),是 Java “一次编写、到处运行”的底层支柱。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











