一、什么是类加载器(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 {
@Override
protected 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() 不委托父类。自定义类加载器的用途?插件、加密、安全、热更新、动态部署等。