Java类加载生命周期为加载→验证→准备→解析→初始化→使用→卸载,其中验证、准备、解析统称连接;各阶段职责明确、顺序固定(解析可延迟),但执行过程可交叉。

Java 类加载机制的生命周期,本质是 JVM 把一个 `.class` 文件从磁盘读入内存、校验安全、组织结构、建立引用、赋予初始值,最终变成可运行的 `Class` 对象的全过程。它不是线性执行完一个再启动下一个,而是阶段间交叉触发、按需推进——但整体顺序和职责边界非常明确。
加载(Loading):把字节码“请进来”
这是整个过程的起点,JVM 做三件事:
- 根据类的全限定名(如 java.lang.String)找到并读取对应的 `.class` 文件字节流(可能来自本地磁盘、JAR 包、网络、甚至动态生成)
- 将字节流解析为方法区中的运行时数据结构(比如常量池、字段表、方法表等)
- 在堆中创建一个 java.lang.Class 实例,作为该类在 JVM 中的运行时代表
注意:此时类还没被“用起来”,静态变量只是分配了内存空间,还没赋值;方法体也还没验证或执行。
连接(Linking):分三步筑牢基础
连接不是单个阶段,而是验证、准备、解析三个子阶段的统称,目标是让类“能用、安全、可定位”。
立即学习“Java免费学习笔记(深入)”;
验证(Verification):防止恶意或损坏的字节码危害 JVM
- 文件格式验证:检查魔数(0xCAFEBABE)、主次版本号是否合法
- 元数据验证:确认类是否有父类、是否继承了 final 类、字段/方法签名是否合规
- 字节码验证:分析方法体控制流,确保跳转不越界、类型使用不混乱
- 符号引用验证:检查常量池中引用的类、字段、方法是否真实存在且可访问
准备(Preparation):给类变量(static 变量)分配内存并设“零值”
- 例如 public static int count; → 此时 count = 0(不是代码里写的默认值)
- 但 public static final int VERSION = 1024; 是例外:若为编译期常量,会直接赋值为 1024
- 引用类型(如 static Object obj;)统一设为 null
解析(Resolution):把常量池里的符号引用转成直接引用
- 符号引用:类似“java/lang/Object#toString()”这样的文本描述
- 直接引用:内存地址、偏移量等可直接使用的指针
- 解析不强制在初始化前完成,某些场景(如接口方法调用)可延迟到首次使用时才解析,支持动态绑定
初始化(Initialization):真正执行 Java 代码的第一步
这是类加载过程中唯一允许用户代码介入的阶段,核心动作是执行
- 按源码顺序执行所有 static 变量的赋值语句(如 static int x = getValue();)
- 执行所有 static 代码块
- 父类优先于子类初始化(若父类未初始化,则先触发父类初始化)
- 接口不强制要求先初始化父接口(除非用到了父接口的静态成员)
触发初始化的典型场景包括:new 对象、读写静态字段(非 final)、调用静态方法、反射 Class.forName()、虚拟机启动时指定主类。
使用与卸载:生命周期的收尾
使用(Using) 阶段没有 JVM 规范定义的具体动作,就是程序正常调用类的字段、方法、创建实例等日常行为。
卸载(Unloading) 极少见,仅发生在该类的 ClassLoader 被垃圾回收时——要求该类所有实例、ClassLoader、Class 对象都不可达。通常只在 OSGi、热部署、Web 容器重载应用等特殊场景发生。


















