一、💡 一句话理解
核心结论
Java 常见的类加载器有:启动类加载器、平台类加载器、应用类加载器和自定义类加载器。前三个由 JDK 提供,开发者也可以继承
ClassLoader实现自己的加载规则。
二、🧭 理论:它是什么
2.1 类加载器是什么,有什么用
类加载器(ClassLoader)是 JVM 中负责查找并加载 Java 类的组件。
Java 代码编译后会生成 .class 字节码文件。当 JVM 第一次需要某个类时,类加载器会找到对应的字节码,将它读入 JVM,并创建可以被程序使用的 Class 对象。
根据类名查找 .class 文件
↓
读取类的字节码
↓
交给 JVM 创建 Class 对象
↓
程序创建对象、调用方法例如执行 new User() 时,JVM 必须先通过类加载器找到并加载 User 类,然后才能创建 User 对象。
类加载器主要有以下作用:
- 加载类:从 JDK、项目目录或 JAR 包中找到需要的类。
- 按需加载:通常在第一次真正使用某个类时才加载,避免一次加载所有类。
- 保护核心类:配合双亲委派机制,避免应用中的同名类替换 Java 核心类。
- 支持特殊场景:可以实现插件加载、热部署、类隔离等功能。
记忆方式
类加载器就是 JVM 的“类文件搬运工”:找到
.class字节码并加载进 JVM,让程序能够创建对象和调用方法。
2.2 四类加载器
| 类加载器 | 主要负责加载 |
|---|---|
| 启动类加载器(Bootstrap ClassLoader) | java.lang 等 Java 核心类 |
| 平台类加载器(Platform ClassLoader) | Java 平台模块中的类 |
| 应用类加载器(Application ClassLoader) | classpath、模块路径中的应用类 |
| 自定义类加载器 | 插件、热部署、类隔离等特殊来源的类 |
版本区别
JDK 8 常说的扩展类加载器(Extension ClassLoader),从 JDK 9 开始被平台类加载器取代。
2.3 这些类具体指什么
2.3.1 核心类
核心类是 Java 程序运行必不可少的基础类,例如:
java.lang.String
java.lang.Object
java.lang.Thread
java.util.ArrayList它们通常由启动类加载器加载。
2.3.2 Java 平台模块中的类
JDK 9 开始,JDK 自带的功能被拆分成多个模块:
| 模块 | 主要功能 |
|---|---|
java.base | 字符串、集合、线程等基础功能 |
java.sql | JDBC 数据库访问 |
java.xml | XML 处理 |
java.net.http | HTTP 客户端 |
java.base 中最基础的类主要由启动类加载器加载,其他一些平台模块中的类由平台类加载器加载。
两者不是完全分开的
核心类本身也属于 Java 平台模块。例如
String属于java.base模块,只是因为它非常基础,所以通常单独称为核心类。
2.3.3 classpath 和模块路径中的应用类
这部分主要包括:
- 自己编写的类,例如
com.example.UserService。 - 项目引入的第三方依赖,例如 Spring、MySQL 驱动中的类。
classpath 告诉 JVM 去哪些目录和 JAR 包中寻找类:
java -cp target/classes:lib/mysql.jar com.example.MainJDK 9 还提供了模块路径(module path),用于查找带有明确模块名称和依赖关系的应用模块。普通 Spring Boot 项目通常主要使用 classpath。它们一般由应用类加载器加载。
快速区分:
Java 运行必需的基础类 → 核心类
JDK 自带的其他功能类 → Java 平台模块中的类
自己写的类和第三方依赖 → classpath 或模块路径中的应用类2.3.4 自定义类加载器加载的类
这不是某一种固定的 Java 类,而是指程序通过自定义类加载器,按照特殊规则加载的类。常见场景有:
- 插件:程序运行时加载外部 JAR,例如 IDE 加载 Java、Git 等插件。
- 热部署:丢弃旧类加载器,再用新类加载器加载修改后的类,减少整个程序重启。
- 类隔离:让不同插件分别使用不同版本的同一个依赖,避免版本冲突。
- 特殊来源:从网络、数据库、加密文件或动态生成的字节码中加载类。
类隔离示例
插件 A 使用 Jackson 2.13,插件 B 使用 Jackson 2.17。即使两个类的完整名称相同,只要定义它们的类加载器不同,JVM 就会把它们视为不同的类。
JVM 判断一个类身份的依据是:
类的完整名称 + 定义它的类加载器一句话理解:普通类加载器按照 JDK 默认规则找类,自定义类加载器允许程序决定去哪里找、怎样读取以及怎样隔离类。
三、⚙️ 理论:它是怎么工作的
类加载器通常采用双亲委派机制:收到加载请求后,先交给父加载器;父加载器找不到时,自己再尝试加载。
应用类加载器 → 平台类加载器 → 启动类加载器这样可以避免核心类被应用程序中的同名类替换。
延伸阅读:13.双亲委派模型
四、🚀 实践:查看类加载器
4.1 最小验证
public class ClassLoaderDemo {
public static void main(String[] args) {
// 当前应用类通常由应用类加载器加载
System.out.println(ClassLoaderDemo.class.getClassLoader());
// String 属于核心类,由启动类加载器加载;Java 中通常显示为 null
System.out.println(String.class.getClassLoader());
// 获取平台类加载器
System.out.println(ClassLoader.getPlatformClassLoader());
}
}String.class.getClassLoader() 返回 null,不代表没有加载器,而是启动类加载器不能直接表示为普通 Java 对象。
五、🎤 面试时怎么说
5.1 30 秒标准回答
Java 常见的类加载器有启动类加载器、平台类加载器、应用类加载器和自定义类加载器。启动类加载器负责核心类,平台类加载器负责平台模块,应用类加载器负责项目 classpath 或模块路径中的类。它们通常遵循双亲委派机制,先让父加载器尝试加载,从而避免核心类被重复加载或被同名类替换。JDK 8 中的扩展类加载器,在 JDK 9 后被平台类加载器取代。
六、📌 总结
- 核心类:启动类加载器。
- 平台类:平台类加载器。
- 项目类:应用类加载器。
- 特殊加载规则:自定义类加载器。
- 记忆顺序:启动 → 平台 → 应用 → 自定义。