JVM 类加载:双亲委派机制

双亲委派机制:一句话说清楚它是啥

一句话总结

双亲委派就是------类加载时,先让父类加载器去加载,父类加载不了,才由自己加载

目的是保证核心类由高层加载器统一加载,防止被替换,确保安全和唯一。


一、什么是"双亲委派"?

"双亲"其实是翻译问题,它不是指"父母双方",而是"父辈"的意思。更准确的说法是"父类委派"。

它的规则只有一条:

当一个类加载器收到加载类的请求时,它不急着自己加载,而是先把请求交给父类加载器去处理。只有父类加载器明确表示"我加载不了",自己才动手。

这个"父",不是 Java 中的继承关系,而是类加载器之间的委托关系


二、类加载器有哪些?

Java 中的类加载器分为四层,从上到下是:

类加载器 实现方式 负责加载
Bootstrap ClassLoader JVM 用 C++ 实现 rt.jar 等核心类库(如 java.lang.*
Extension ClassLoader Java 实现 jre/lib/ext 目录下的扩展类
Application ClassLoader Java 实现 classpath 下的用户类(你的代码)
自定义 ClassLoader 继承 ClassLoader 特殊需求,如网络加载、热部署

它们之间形成一条链:

复制代码
自定义 → Application → Extension → Bootstrap

加载请求从下往上层层委派,一旦某一层能加载,就直接返回,不再往下。


三、为什么要有双亲委派?

1. 防止核心类被篡改

试想:如果你写了一个 java.lang.String,放在项目里。

如果没有双亲委派,Application ClassLoader 可能会加载你写的这个"假" String,那整个系统就乱了。

但因为有双亲委派,加载请求会先被委派到 Bootstrap ClassLoader,它从 rt.jar 中加载了真正的 String,你的类根本不会被加载。

✅ 所以,你永远无法替换核心类

2. 避免类重复加载

同一个类,比如 java.util.ArrayList,如果被多个类加载器各自加载,就会出现多个 Class 对象。

这会导致:

  • instanceof 判断失败;
  • 类型转换异常;
  • 静态变量不共享。

双亲委派确保这类核心类只被最顶层的加载器加载一次,保证唯一性。

3. 安全

核心类库由最可信的 Bootstrap ClassLoader 加载,它不走 Java 层代码,不受用户控制。

这种自顶向下的信任链,让 JVM 能抵御恶意代码的攻击。


四、双亲委派是怎么实现的?

核心就在 ClassLoader.loadClass() 方法里。

JDK 8 中的关键逻辑如下:

java 复制代码
protected Class<?> loadClass(String name, boolean resolve) {
    // 1. 先查自己是否已加载
    Class<?> c = findLoadedClass(name);
    if (c == null) {
        try {
            // 2. 有父类,先让父类加载
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                // 父为 null,表示使用 Bootstrap
                c = findBootstrapClassOrNull(name);
            }
        } catch (ClassNotFoundException e) {
            // 父类加载失败,继续
        }
        // 3. 父类没加载成功,自己加载
        if (c == null) {
            c = findClass(name);
        }
    }
    return c;
}

这个方法定义了标准流程

查缓存 → 委派父类 → 自己加载。

除非你重写它,否则所有类加载器都必须遵守。


五、双亲委派能打破吗?

能。通过重写 loadClass 方法,可以改成"先自己加载,再委派父类",这就是打破双亲委派

常见场景:

  • Tomcat:每个 Web 应用用独立类加载器,避免应用之间类冲突;
  • OSGi:模块化框架,支持不同模块用不同版本的同一个库;
  • 热部署:重新加载类而不重启 JVM。

代价:

  • 类唯一性没了;
  • 需要自己处理类隔离、冲突、卸载等问题;
  • 复杂度高,一般只在框架层面使用。

相关推荐
用户298698530142 小时前
Java HTML 转 Word 完整指南
java·后端
渣哥3 小时前
原来公平锁和非公平锁差别这么大
java
渣哥3 小时前
99% 的人没搞懂:Semaphore 到底是干啥的?
java
J2K3 小时前
JDK都25了,你还没用过ZGC?那真得补补课了
java·jvm·后端
EMQX3 小时前
ESP32 + MCP over MQTT:通过大模型控制智能硬件设备
后端·mcp
郭京京3 小时前
go框架gin(中)
后端·go
郭京京3 小时前
go框架gin(下)
后端·go
kfyty7253 小时前
不依赖第三方,不销毁重建,loveqq 框架如何原生实现动态线程池?
java·架构
林树的编程频道3 小时前
单例模式的推导
后端