当前位置: 首页 > news >正文

java的类加载器及其双亲委派机制

为什么要设计类加载器?

个人理解,仅供参考。java是跨平台的,运行的是字节码,每次运行时都是读取字节码然后执行字节码,类加载器就是把字节码读取进内存的一个工具,进入内存后才能有后续的步骤。而字节码的来源可以多种多样,可以是java代码编译出的一个.class文件,也可以是从网络或其他文件中读取出的二进制字节流。有了类加载器你就可以自己定义去哪里读取字节码。简而言之,没有类加载器,java字节码就无法进入内存

双亲委派机制的“双亲”是指哪两个?

即当Java程序需要使用某个类时,负责加载这个类的类加载器会首先把加载请求委托给它的父加载器,而不是自己直接加载,这种机制被称为双亲委派机制。那么,这里的“双亲”又是指哪两个呢?

请看官方文档:https://docs.oracle.com/javase/tutorial/ext/basics/load.html

The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.

翻译:Java 平台采用委派模型来加载类。其基本思想是,每个类加载器都有一个 “父” 类加载器。在加载一个类时,类加载器会先将查找该类的任务 “委派” 给它的父类加载器,然后才会尝试自己去查找这个类。

我也一直在困惑这个“双亲”到底是指谁?经过不断搜索,结合官方文档,首先可以确定——“双亲委派”这个翻译是不太准确的!表意不明!这里的“parent”和普通的class loader是没有继承关系的,不能算“亲”,但是鉴于毕竟是翻译,允许有点偏差,这一点我觉得还可以接受。其次,官方文档里没有提到“双”!不知道这个“双”是从何而来!非常令人迷惑!所以网上有人提到“双亲委派”是个错误翻译。

还有一种说法,也是我自己揣测过的,就是一个自定义类加载类时,会先委托给扩展类加载器,再由扩展类加载器委托给启动类加载器。这样就出现了“双亲”。图示如下

既然反正最终也都是要交给启动类加载器去加载,

那么多层加载器又有什么意义呢?

这就要老生常谈地说起加载器的分类:

1、启动类加载器。只加载java的核心类(<JAVA_HOME>\lib下的)。由于java核心类是所有程序运行的基础,一定要确保核心类的正常运行,所以把核心类单独划出来,交由专门的启动类加载器来加载,避免其他类来干扰。

2、扩展类加载器。负责加载<JAVA_HOME>\lib/ext下的类。一些自定义的类也可以放到该目录下交由扩展类加载器加载。

3、应用程序类加载器(又叫系统类加载器)。负责加载用户类路径上所指定的库。

这样分类加载的好处(来自百度)

避免类的重复加载‌:通过双亲委派机制,当一个类加载器收到类加载请求时,它会先将该请求委派给它的父类加载器去尝试加载。只有当父类加载器无法加载该类时,子类加载器才会尝试加载。这样可以确保同一个类只被加载一次,避免了类的重复加载,提高了加载效率‌。

保证类的一致性‌:由于父类加载器优先加载类,可以保证类的一致性,避免了不同类加载器加载同一个类的问题。这有助于维护系统的稳定性和一致性‌。

保护核心类库的安全性‌:JVM中的根类加载器负责加载核心类库,如java.lang包下的类。由于根类加载器是由JVM实现的,无法通过Java代码直接访问,这样可以防止恶意代码替换核心类库,保护系统的安全性‌。

提供扩展机制‌:双亲委派机制允许开发人员自定义类加载器,实现特定的加载策略,从而扩展Java的类加载机制。这种灵活性使得Java能够适应不同的应用场景和需求‌。

那么,又一个问题让我迷惑了:既然有双亲委派机制,而且扩展类加载器中也是有委派机制的,那么最终不就都会由启动类加载器来加载了吗?又这样分层还有什么意义?

实际,启动类加载器在判断到所加载的类不是核心类后会拒绝加载,最终扩展类还是由扩展类加载器加载的。

与java 1.2版本之前的旧代码的兼容

之前的自定义加载器都是重写loadClass()来加载类的,出现双亲委派机制后,为兼容旧代码,就又新增了一个方法findClass(),并改写了loadClass()使其符合双亲委派:有父加载器,使用父加载器加载,没有父加载器就使用启动类加载器加载,仍然失败就调用自己的findClass()加载。这样,如果原来的自定义加载器重写了loadClass()并且没有调用super.loadClass(),则是完全不受影响的。如果调用了super.loadClass()呢?  那就得改,引导用户按新规则来。

相关文章:

  • 解决docker安装OpenWebUI 报错 500
  • Node.js 数据库 CRUD 项目示例
  • uni-app/微信小程序接入腾讯位置服务地图选点插件
  • STM32F407实现SD卡的读写功能
  • #[特殊字符]Rhino建模教程 · 第一章:正方体建模入门
  • docker 启用portainer,容器管理软件
  • Flowable工程化改造相关文档
  • AI大模型如何重塑科研范式:从“假说驱动”到“数据涌现”
  • 11【模块学习】DS18B20(一):使用学习
  • 免费的内网穿刺工具和免费域名
  • **Windows 系统**的常用快捷键大全
  • C语言实战:用Pygame打造高难度水果消消乐游戏
  • Linux路漫漫
  • 千树万树梨花开
  • 【18】Strongswan encoding详解 message2
  • 面试题:请描述一下你在项目中是如何进行性能优化的?针对哪些方面进行了优化,采取了哪些具体的措施?
  • 【JavaScript】二十一、日期对象
  • 数据结构*集合框架顺序表-ArrayList
  • 网络的起点:深入解析计算机网络中的网络接口层
  • 在JavaScript中实现文件下载完成后自动打开
  • 中青报:“猿辅导员工猝死”事件上热搜,是对健康职场环境的共同关切
  • 国铁集团:一季度全国海铁运输商品车同比增长33.62%
  • 神舟二十号3名航天员顺利进驻中国空间站
  • 主刀完成3万余例手术,81岁神经外科学专家徐启武逝世
  • 十三届全国政协经济委员会副主任张效廉严重违纪违法被开除党籍
  • 搜索市场战火延伸:OpenAI虎视眈眈,欲收购谷歌浏览器