Java类加载器ClassLoader的双亲委派模型

本文详细解析了Java虚拟机中的类加载器及其双亲委派机制,包括引导类加载器、扩展类加载器和应用类加载器的工作原理,以及这种机制如何保障程序的安全性和防止类的重复加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类加载器

我们编写的.java文件被编译器编译成.class的字节码文件,类加载器ClassLoader负责将这些字节码文件加载到内存中去执行。
JVM提供了三种类加载器:
引导类加载器Bootstrap:最顶层类加载器,负责加载JDK核心类库,C++语言实现
扩展类加载器ExtClassLoader:负责加载JDK扩展类库,Java语言实现
应用类加载器AppClassLoader:负责加载我们自己定义的类和第三方jar包中的类,Java语言实现
AppClassLoader的父加载器是ExtClassLoader,ExtClassLoader的父加载器是Bootstrap。

双亲委派模型

双亲委派机制:当一个类加载器收到类加载的请求时,它首先不会自己去尝试加载这个类,而是把这个请求委派给父加载器完成,每个类加载器都是如此,因此所有的加载请求最终都会传送到顶层的引导类加载器中,只有当父加载器在自己的搜索范围内找不到指定的类时,子加载器才会尝试自己去加载。如下图所示:
在这里插入图片描述加载过程:
当应用类加载器接到加载某个类的任务时,例如:java.lang.String

(1)会先在内存中搜索这个类是否加载过,如果是,就返回这个类的Class对象,不去加载。

(2)如果没有找到,即没有加载过,会把这个任务提交给父加载器。

当扩展类加载器接到类加载的请求时

(1)会先在内存中搜索这个类是否加载过,如果是,就返回这个类的Class对象,不去加载。

(2)如果没有找到,即没有加载过,会把这个任务提交给父加载器。

当引导类加载器接到类加载的请求时

(1)会先在内存中搜索这个类是否加载过,如果是,就返回这个类的Class对象,不去加载。

(2)如果没有找到,即没有加载过,去它负责的范围内尝试加载。

① 如果能够加载,那么就自己加载并返回这个类的Class对象,结束。

② 如果不能加载,那么会把这个任务往回传,让子加载器去加载。

扩展类加载器接到父加载器返回的任务后,去它负责的范围内尝试加载。

① 如果能够加载,那么就自己加载并返回这个类的Class对象,结束。

② 如果不能加载,那么会把这个任务往回传,让子加载器去加载。

应用类加载器接到父加载器返回的任务后,去它负责的范围内尝试加载。

① 如果能够加载,那么就自己加载并返回这个类的Class对象,结束。

② 如果不能加载,那么就抛出ClassNotFoundException

为什么要用这种类加载机制

你可能会想到两个问题:
(1)为什么不用就近原则,子加载器能够加载就让子加载器加载好了,却要委托给父加载器加载?
(2)检查一个类是否加载过为什么要重复搜索,既然加载请求最终要传给顶层的引导类加载器,那么为什么不一开始就交给顶层的引导类加载器,自顶向下尝试加载?

对于问题(1):保证程序的安全性,防止系统级别的类被替换。例如类java.lang.Object,最终要委派给处于模型最顶层的引导类加载器进行加载,它会优先jdk中提供的Object类,而不是我们自己定义的。
验证:我们自己定义一个Object类,包名也为java.lang:

package java.lang;

public class Object {
    public static void main(String[] args) {
        System.out.println("自定义的Object类");
    }
}

发现运行报错:
在这里插入图片描述
明明在String类中定义了main方法,为什么提示找不到呢?因为实际加载的是核心类库中Object类,里面是没有main方法的。

对于问题(2):防止同一个类被重复加载。每层类加载器都有自己的确认逻辑,同一个类被不同的类加载器加载,会被识别为不同的类。只有每层的类加载器都确认自己没有加载过,才能最终判定这个类没有被加载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值