大家好,本篇带你从头到尾、一步不落地吃透 Java 类加载机制 。不管是面试、调优、还是理解 JVM 底层原理,类加载都是绕不开的核心知识点。我会用清晰、直白、可直接背诵的方式,把整个流程讲透。
一、什么是类加载?
简单说:类加载就是 JVM 把 .class 文件读进内存,并对数据进行校验、转换、解析、初始化,最终形成可以被虚拟机直接使用的 Java 类型的过程。
一个类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期分为 7 个阶段:
加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
其中:验证 + 准备 + 解析 = 链接(Linking)

二、类加载全过程详解
1. 加载(Loading)
加载是类加载的第一个阶段,做三件事:
- 通过一个类的全限定名(包名 + 类名)获取定义此类的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的
java.lang.Class对象,作为访问这个类的入口。
一句话总结:把 class 文件读进内存,生成 Class 对象。
2. 验证(Verification)
目的:保证 .class 字节流符合虚拟机规范,不会危害虚拟机安全。
主要做这些检查:
- 文件格式验证(魔数、版本号等)
- 元数据验证(类的结构是否合法)
- 字节码验证(程序逻辑安全)
- 符号引用验证
一句话总结:检查 class 文件是否合法、安全、可运行。
3. 准备(Preparation)
为类的静态变量分配内存,并设置默认初始值。
重点:
- 只处理 static 变量,在方法区分配内存。
- 给的是默认初始值 :
0 / false / null。 static final常量:编译期已确定值,准备阶段直接赋值。- 实例变量不参与此阶段,实例变量是在对象创建时在堆中分配。
一句话总结:给静态变量分配内存并赋默认值,static final 常量直接赋值。
4. 解析(Resolution)
将常量池内的符号引用替换为直接引用。
- 符号引用:字面量描述,不关心内存位置。
- 直接引用:直接指向内存地址的指针或偏移量。
解析主要针对:类 / 接口、字段、类方法、接口方法等。
一句话总结:把 "名字" 变成真正的 "内存地址"。
5. 初始化(Initialization)
这是类加载的最后一步 ,也是真正开始执行我们写的 Java 代码的阶段。
做什么:执行 <clinit>() 方法,按顺序执行:
- 静态变量赋值
- 静态代码块
什么时候触发初始化?(面试高频)
- new 对象
- 访问静态变量 / 静态方法
- 反射调用
- 初始化子类时,父类先初始化
- 启动时执行主类
一句话总结:执行静态代码和静态赋值,只有主动使用类时才会初始化。
三、类加载全过程(可直接背诵版)
Java 类的完整生命周期从加载 开始,通过类的全限定名读取 .class 字节流到内存,转换为方法区数据结构并生成 Class 对象;随后进入链接 阶段:先验证 字节码安全合法,再准备 为静态变量分配内存并赋默认值(static final 常量直接赋值,实例变量不参与),最后解析 将符号引用转为直接引用;接着进入初始化 阶段,执行 <clinit>() 完成静态变量赋值与静态代码块执行;之后进入使用 阶段,可创建对象、调用方法;最终在无引用、无实例、类加载器被回收时卸载 ,Class 对象被 GC 回收。
四、面试高频考点(背会直接拿分)
-
**准备阶段赋什么值?**默认值:0、false、null,不是代码里写的值。
-
**static final 常量在哪个阶段赋值?**编译期确定,准备阶段直接赋值。
-
**实例变量在准备阶段分配吗?**不分配,实例变量在创建对象时在堆里分配。
-
**初始化阶段执行什么?**静态变量赋值 + 静态代码块。
-
**哪些情况会触发类初始化?**new、访问静态成员、反射、子类初始化、主类启动。
五、总结
类加载是 Java 运行的基石,整个过程可以概括为:
加载(读文件) → 链接(验、备、解) → 初始化(执代码) → 使用 → 卸载
只要把这 5 步的作用、关键点、面试坑点记牢,JVM 类加载这一块你就彻底稳了。