java类加载过程分为加载、验证、准备、解析、初始化五阶段:加载将字节码转为class对象;验证校验安全性;准备为static变量设默认值;解析将符号引用转直接引用;初始化执行方法赋值与静态块。

Java 类加载过程不是一次性完成的机械流水线,而是由 JVM 按需驱动、阶段间可交叉、但整体有逻辑依赖的一组协作行为。核心五阶段——加载、验证、准备、解析、初始化——各自承担明确职责,且触发时机和执行边界非常关键。
加载:把字节码变成内存里的 Class 对象
这是整个过程的起点,由类加载器(ClassLoader)主导。JVM 根据全限定名定位 .class 文件(可能来自本地磁盘、JAR 包、网络甚至动态生成),读取二进制流,然后在 Metaspace(或旧版的方法区)中创建运行时数据结构,并生成一个 java.lang.Class 实例作为该类所有元信息的统一入口。
注意:此时只是“结构就位”,静态变量还没分配空间,更不会执行任何赋值语句;实例变量完全不参与;也不会触发父类或接口的任何动作。
验证:确保字节码安全合规
验证发生在类数据进入 Metaspace 后、被正式使用前,是 JVM 的安全守门员。它不做修改,只做校验,失败则抛出 VerifyError 并终止加载。四层检查包括:
- 文件格式验证:检查魔数(0xCAFEBABE)、主次版本号、常量池格式等,确保能被正确解析
- 元数据验证:检查继承关系是否合法(如 final 类不能被继承)、父类是否存在等语义问题
- 字节码验证:分析方法体控制流与数据流,防止跳转越界、类型错配等运行时风险
- 符号引用验证:确认常量池中的类、字段、方法引用是否真实存在且可访问
准备与解析:静态变量占位 + 符号引用落地
准备阶段为 类变量(static 字段) 在 Metaspace 分配内存,并设 Java 规定的默认值(如 int → 0,reference → null)。特别注意:final static 编译期常量(如 public static final int PORT = 8080;)不在此阶段赋值,而是直接内联进调用方字节码,跳过本类初始化。
解析阶段负责将常量池中的 符号引用(比如 “#42 表示 java.util.List 的 add 方法”)转换成 直接引用(如内存中某个 Method 对象的实际地址)。这个阶段通常是懒执行的——只有首次主动使用该引用时才触发,比如第一次调用某个静态方法、第一次访问某个静态字段(非 final)。
初始化:执行用户代码的唯一阶段
这是唯一会真正运行 Java 代码的阶段,JVM 会执行类构造器
- new 创建实例
- 读写静态字段(非 final)
- 调用静态方法
- 反射调用(如 Class.forName)
- 初始化子类时,先触发父类初始化
- 虚拟机启动时,执行 main 方法所在的主类
一旦触发初始化,JVM 会确保其继承链上所有尚未初始化的父类也完成初始化,并按源码顺序执行所有静态赋值语句和静态块。而像通过子类引用父类静态字段、定义数组类型、访问编译期常量等,都属于 被动引用,不会触发初始化。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











