深入理解Java类加载机制中的双亲委派模型--根据源码探讨

chatgpt/2023/9/27 16:23:59

前言:
今天和大家探讨一道Java中经典的面试题,这道面试题经常出现在各个公司的面试中,本篇文章主要讲解ava类加载机制中的双亲委派模型的知识。该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。

如果文章有什么需要改进的地方欢迎大佬提出,对大佬有帮助希望可以支持下哦~

小威在此先感谢各位小伙伴儿了😁

在这里插入图片描述

以下正文开始

文章目录

  • Java中的类加载器
    • 启动类加载器(Bootstrap ClassLoader)
    • 扩展类加载器(Extension ClassLoader)
    • 应用程序类加载器(Application ClassLoader)
    • 自定义类加载器(Custom ClassLoader)
  • 双亲委派模型
  • 双亲委派模型源码
  • 如何打破双亲委派模型

Java中的类加载器

在介绍双亲委派模型之前,首先先介绍下Java中的类加载器。
在这里插入图片描述

启动类加载器(Bootstrap ClassLoader)

首先先介绍下类加载器中的重量级器物,就是大名鼎鼎–启动类加载器。

为什么说他是重量级的恩,因为它是Java类加载器层次结构的最顶层,由虚拟机实现,用于加载Java核心类库,如java.lang和java.util等。

既然是最顶层的类加载器,我们就康康它有什么作用:

启动类加载器是由C/C++编写的,无法直接在Java代码中获取其引用。 它负责加载Java运行时环境所需的基本类。

扩展类加载器(Extension ClassLoader)

接着我们看一下Java加载器中的第二号人物–扩展类加载器。

扩展类加载器是由Java编写的,它是启动类加载器的子类。 它负责加载Java扩展类库,位于jre/lib/ext路径下的JAR文件。
扩展类加载器可以通过java.ext.dirs系统属性来指定其他目录作为扩展类库的路径。

应用程序类加载器(Application ClassLoader)

接着介绍最底层的加载器–应用程序类加载器。

应用程序类加载器是Java类加载器层次结构的最底层,也称为系统类加载器。
它负责加载应用程序类路径(Classpath)下的类,包括开发者自己编写的类和第三方库。
应用程序类加载器可以通过-classpath或-cp选项来指定加载类的路径。

自定义类加载器(Custom ClassLoader)

除了上述系统类的加载器,我们开发者还可以自定义加载器-惊不惊喜,意不意外。

在这里插入图片描述

自定义类加载器是开发者根据需求编写的自定义加载器,继承自ClassLoader类
它可以根据特定的加载规则和需求,从不同的来源加载类,比如本地文件系统、网络等。
自定义类加载器需要实现findClass()方法,指定类的加载规则,然后通过defineClass()方法加载类的字节码。

双亲委派模型

看到这里,上我们的重头菜,这块知识是面试中的重点内容。

在这里插入图片描述

双亲委派(Parent Delegation)是Java类加载机制中一种重要的实现方式,它通过一种递归的方式在类加载器之间建立了父子关系,并且定义了类加载的优先级。该模型主要用于解决类加载的冲突和隔离问题,保证Java应用程序的稳定性和安全性。

在Java类加载机制中,每个类加载器都有一个父加载器。当一个类加载器需要加载一个类时,它首先会委托给它的父加载器进行加载。只有当父加载器无法加载时,子加载器才会尝试加载。这种递归的委派模型可以形成一个类加载器的层次结构,称为类加载器树。

我看了《深入理解Java虚拟机-第三版》中的讲解,挺详细的,这里分享给大家:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父类加载器反馈自己无法加载这个请求时,子加载器才会尝试自己去加载。
在这里插入图片描述

双亲委派模型源码

首先可以先尝试自己看下源码,非常通俗易懂:

protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {// 首先,检查类是否已经被加载Class<?> c = findLoadedClass(name);if (c == null) {try {if (parent != null) {// 如果父类加载器存在,则委派给父类加载器c = parent.loadClass(name, false);} else {// 否则,使用引导类加载器进行加载c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// 如果父类加载器也无法找到类,则尝试自己加载c = findClass(name);}}if (resolve) {resolveClass(c);}return c;
}

在上面的源码中,我们可以看到双亲委派机制的体现。当loadClass方法被调用时,首先会检查该类是否已经被加载。如果没有加载,那么会按照以下步骤进行处理:

  1. 首先,调用findLoadedClass(name)方法检查类是否已经被其他类加载器加载过。如果是,则直接返回该类的Class对象。

  2. 如果这个类还未加载,则尝试委派给父类加载器加载。通过parent.loadClass(name, false)方法,将类加载任务传递给父类加载器。这个过程中,父类加载器会重复执行上述流程,直到达到引导类加载器为止。

  3. 如果所有的父类加载器都无法加载该类,那么会尝试使用启动类加载器加载。这是Java类加载器层次结构的最顶层。

  4. 如果引导类加载器仍然无法找到所需的类,就会调用findClass(name)方法在当前类加载器的作用域内查找并加载该类。

  5. 到最后,如果resolve参数为true,就会调用resolveClass©方法进一步解析和链接该类。

在这里插入图片描述

如何打破双亲委派模型

其实双亲委派模型并不是具有强制性约束的模型,虽然它有助于保证类的隔离和加载的顺序,但有时候我们可能需要打破这种机制,比如我们在特殊情况下需要自定义类加载逻辑或实现热部署的时候。

上周面试问道了这个问题,所以在这里也介绍几种打破Java中双亲委派机制的方法:

  1. 自定义类加载器:我们自定义一个继承自ClassLoader的类加载器,重写loadClass方法,可以实现自己的类加载逻辑。在我们定义的这个方法中,可以在需要时跳过父类加载器并直接加载类,从而打破双亲委派机制。但是,在自定义类加载器中打破双亲委派机制可能会导致类的隔离性和安全性问题,所以我们在使用时要慎重。

  2. 线程上下文类加载器:Java中提供了线程上下文类加载器(Thread Context ClassLoader)的概念,它可以在某些情况下打破双亲委派机制。例如,在JNDI、SPI(Service Provider Interface)和一些框架中,线程上下文类加载器可以用来加载指定的类,从而不受双亲委派机制的限制。

  3. 通过反射机制:使用反射机制可以直接调用Class类的defineClass方法,这样可以绕过双亲委派机制直接加载指定的类。但是,在使用这种方式时,我们需要自行处理类加载的顺序和依赖关系,因为双亲委派机制不再起作用。

综上所述,不正确地使用或滥用这些方法可能导致类加载冲突、安全问题以及代码的不稳定性 ,因此我们还需要在明确的需求和充分的理解下使用(面试会背诵就行【手动狗头】)。

在这里插入图片描述
文章到这里就先结束了,感兴趣的可以订阅专栏哈,后续会继续分享相关的知识点。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-5312842.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

无需魔法三分钟上线Midjourney应用,【附源码】【示例】

ps:我是标题党&#xff0c;目前还没见过三分钟完成任务的&#xff0c;三分钟只能打通Midjourney接口。我花了一天时间接入应用哈哈哈&#xff01; 首先&#xff0c;我要感谢laf赞助我&#xff0c;让我可以免费使用Midjourney进行开发和测试。来自白嫖党的快乐。 其次&#xff…

《kubernetes权威指南》-第一章学习笔记

1.什么是kubernetes&#xff1f; kubernetes是一个全新的基于容器技术的分布式架构领先方案。 2.为什么要用kubernetes&#xff1f; 使用kubernetes提供的解决方案能够减少30%的开发成本&#xff0c;并且能够将开发人员的精力更加集中于业务本身&#xff0c;同时可以降低系统…

tinkerCAD案例:29. New: Cruising with Shapes 新功能:与形状一起Cruising

tinkerCAD案例&#xff1a;29. New: Cruising with Shapes 新功能&#xff1a;与形状一起Cruising 原文&#xff1a;有动图演示 Stacking and assembling shapes has never been easier with Tinkercad’s new Cruise tool! 使用Tinkercad的Cruising工具堆叠和组装形状从未如…

【力扣周赛】第 356 场周赛(数位DP)

文章目录 Q1&#xff1a;6917. 满足目标工作时长的员工数目&#xff08;简单枚举模拟题&#xff09;Q2&#xff1a;6900. 统计完全子数组的数目&#xff08;双指针滑动窗口&#xff09;Q3&#xff1a;6918. 包含三个字符串的最短字符串Q4&#xff1a;6957. 统计范围内的步进数字…

python错误提示:AttributeError: ‘DataFrame‘ object has no attribute ‘append‘

错误提示&#xff1a; AttributeError: ‘DataFrame’ object has no attribute ‘append’ 出现错误的代码&#xff1a; df_train_log pd.DataFrame() df_train_log df_train_log.append(log_train, ignore_indexTrue)原因&#xff1a; append包在pandas被弃用 解决方法&…

Python小红书旋转验证码识别

本周免费接了一个用户的需求&#xff0c;研究了一下小红书旋转验证码。刚开始小瞧了它&#xff0c;觉得它应该没有百度旋转验证码那么难&#xff0c;毕竟图像没有干扰&#xff0c;需要的训练样本就可以很少。然而事情并没有这么简单&#xff0c;所以记录一下。 首先看一下最终…

好用的备忘录app如何使用预设提醒功能?

备忘录的预设提醒功能是什么意思呢&#xff1f;就是在使用的过程中&#xff0c;提前预设好常用的提醒的时间&#xff0c;比如明天某个时间点、下周某个时间点等等&#xff0c;在需要设置提醒的时候&#xff0c;就可以直接使用。好用的备忘录app如何使用预设提醒功能&#xff1f…

AP5101 高压线性恒流电源驱动 输入 24-36V 输出3串18V LED线性恒流驱动方案

1,输入 24V-36V 输出3串18V 直亮 参考BOM 表如下 2,输入 24V-36V 输出3串18V 直亮 参考线路图 如下​ 3&#xff0c;产品描述 AP5101B 是一款高压线性 LED 恒流芯片&#xff0c;外围简单、内置功率管&#xff0c;适用于6- 60V 输入的高精度降压 LED 恒流驱动芯片。最大…
推荐文章