了解类加载器吗?类加载器的类型有哪些?
一、什么是类加载器(ClassLoader)
类加载器是 Java 虚拟机中的一部分,负责将 .class 文件加载到 JVM 内存中,生成对应的 Class 对象。
Java 程序中所有的类在使用前都必须通过类加载器加载进 JVM,才能被执行。
二、类加载器的作用
- 加载 .class文件到内存中。
- 将字节码转换为 JVM 能识别的 Class对象。
- 实现类的 命名空间隔离。
- 支持 模块化开发(如插件机制、自定义业务模块加载)。
三、类加载器的分类(JVM 内置 + 用户自定义)
1. 启动类加载器(Bootstrap ClassLoader)
- 作用: 加载 JVM 的核心类库,如 java.lang.*、java.util.*等。
- 加载路径: JAVA_HOME/lib目录中的类(如rt.jar)。
- 实现: 由 C/C++ 实现,是 JVM 的一部分。
- 特点: 不是 Java 类,不能被直接引用或操作。
2. 扩展类加载器(Extension ClassLoader)
- 作用: 加载 Java 扩展类库。
- 加载路径: JAVA_HOME/lib/ext/目录或由java.ext.dirs系统变量指定的路径。
- 父加载器: Bootstrap ClassLoader。
- 类名: sun.misc.Launcher$ExtClassLoader。
3. 应用类加载器 / 系统类加载器(Application ClassLoader)
- 作用: 加载用户类路径(classpath)下的类文件。
- 加载路径: 当前应用的 classpath(如 jar 包或类文件所在目录)。
- 父加载器: Extension ClassLoader。
- 类名: sun.misc.Launcher$AppClassLoader。
4. 自定义类加载器(Custom ClassLoader)
- 
作用: 开发者可以继承 java.lang.ClassLoader实现自己的加载逻辑。
- 
使用场景: - 热部署
- 模块化(如 OSGi)
- 插件系统
- 加密 class 文件
 
- 
常见方式: - 继承 ClassLoader并重写findClass()方法
- 调用 defineClass()定义类对象
 
- 继承 
四、类加载器的层次结构图
┌──────────────────────────┐
│ Bootstrap ClassLoader    │
│ (C++实现, 加载核心类库)     │
└──────────┬───────────────┘↓
┌──────────────────────────┐
│ Extension ClassLoader    │
│ (加载 ext 目录类)          │
└──────────┬───────────────┘↓
┌──────────────────────────┐
│ Application ClassLoader  │
│ (加载classpath下类)        │
└──────────┬───────────────┘↓
┌──────────────────────────┐
│ 自定义 ClassLoader       │
│ (可指定加载路径/策略)     │
└──────────────────────────┘
五、双亲委派机制(Parent Delegation Model)
定义:
类加载器在加载类时,首先会 将加载请求委托给父加载器,由顶层的 Bootstrap 开始查找,只有在父加载器找不到时,才由当前加载器加载。
加载流程:
- 当前类加载器收到类加载请求。
- 委托给父类加载器。
- 如果父类无法加载,才由当前加载器尝试加载。
优点:
- 避免类的重复加载。
- 防止用户自定义类覆盖 JDK 核心类(如 java.lang.String)。
举例说明:
public class Test {public static void main(String[] args) {System.out.println(String.class.getClassLoader()); // null(Bootstrap)System.out.println(Test.class.getClassLoader());   // AppClassLoader}
}
六、自定义类加载器示例
public class MyClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {byte[] data = loadClassData(name); // 从文件或网络中读取字节数组return defineClass(name, data, 0, data.length);}
}
七、线程上下文类加载器(ContextClassLoader)
定义:
- 每个线程可以设置自己的类加载器,用于动态加载类或资源。
- 默认是 Application ClassLoader。
用途:
- 在 Java SPI(Service Provider Interface)中尤为重要。
- 解决双亲委派带来的灵活性限制。
Thread.currentThread().setContextClassLoader(new MyClassLoader());
八、类加载器相关方法(Java API)
| 方法 | 说明 | 
|---|---|
| loadClass(String name) | 加载类(会委托给父类) | 
| findClass(String name) | 查找类(自定义类加载核心) | 
| defineClass(...) | 将字节数组转为 Class 对象 | 
| getParent() | 获取父加载器 | 
| getClassLoader() | 获取当前类的加载器 | 
九、面试常问点总结
| 问题 | 要点回答 | 
|---|---|
| 什么是类加载器? | 将 .class加载进内存,生成 Class 对象。 | 
| JVM 有哪些类加载器? | 启动类、扩展类、应用类、自定义类加载器。 | 
| 双亲委派模型是什么? | 加载委托给父加载器,避免重复 & 保证安全性。 | 
| 如何打破双亲委派? | 重写 loadClass()不委托父类。 | 
| 自定义类加载器的用途? | 插件、加密、安全、热更新、动态部署等。 | 
