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。

代价:

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

相关推荐
小树懒(-_-)23 分钟前
SEO:Java项
java·开发语言
用户214118326360241 分钟前
Qwen3-VL 接口部署全攻略:从源码到 Docker,手把手教你玩转多模态调用
后端
TeleostNaCl42 分钟前
如何在 IDEA 中使用 Proguard 自动混淆 Gradle 编译的Java 项目
android·java·经验分享·kotlin·gradle·intellij-idea
小蕾Java1 小时前
IntelliJ IDEA 2025:最新使用图文教程!
java·ide·intellij-idea
聪明的笨猪猪1 小时前
Java “线程池(1)”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
Miraitowa_cheems1 小时前
LeetCode算法日记 - Day 63: 图像渲染、岛屿数量
java·数据结构·算法·leetcode·决策树·贪心算法·深度优先
databook1 小时前
Manim实现旋转扭曲特效
后端·python·动效
karry_k1 小时前
ThreadLocal原理以及内存泄漏
java·后端·面试
MrSun的博客1 小时前
数据源切换之道
后端
Keepreal4961 小时前
1小时快速上手SpringBoot,熟练掌握CRUD
spring boot·后端