类加载机制——双亲委派机制

news2025/2/23 19:08:05

类加载器分类

类加载器

类加载器(英文:ClassLoader)负责加载 .class 字节码文件,.class 字节码文件在文件开头有特定的文件标识。ClassLoader 只负责 .class 字节码文件的加载,至于它是否可以运行,则由 Execution Engine 决定。

images

JVM 中类加载器分为四种:前三种为虚拟机自带的加载器。

  • 启动类加载器(Bootstrap):使用 C++ 语言编写的类加载器,在Java环境下看不到

    负责加载 JAVA_HOME/lib/.jar 里所有的 class。由 C++ 实现,不是 ClassLoader 子类

  • 扩展类加载器(Extension):sun.misc.Launcher.ExtClassLoader

    负责加载 Java 平台中扩展功能的一些 jar 包,包括 JAVA_HOME/lib/.jar 或 -Djava.ext.dirs 参数指定目录下的 jar 包、以及 JAVA_HOME/lib/ext/classes 目录下的 class。

  • 应用类加载器(AppClassLoader):sun.misc.Launcher.AppClassLoader

    也叫系统类加载器,负责加载classpath中指定的 jar 包及目录中的 class

  • 自定义类加载器:程序员自己开发一个类继承 java.lang.ClassLoader,定制类加载方式

父子关系1:启动类加载器是扩展类加载器的父加载器

父子关系2:扩展类加载器是应用类加载器的父加载器

代码测试

// 1.获取Person类的Class对象
// 2.通过Class对象进一步获取它的类加载器对象
ClassLoader appClassLoader = Person.class.getClassLoader();

// 3.获取appClassLoader的全类名
String appClassLoaderName = appClassLoader.getClass().getName();

// 4.打印appClassLoader的全类名
// sun.misc.Launcher$AppClassLoader
System.out.println("appClassLoaderName = " + appClassLoaderName);

// 5.通过appClassLoader获取扩展类加载器(父加载器)
ClassLoader extClassLoader = appClassLoader.getParent();

// 6.获取extClassLoader的全类名
String extClassLoaderName = extClassLoader.getClass().getName();

// 7.打印extClassLoader的全类名
// sun.misc.Launcher$ExtClassLoader
System.out.println("extClassLoaderName = " + extClassLoaderName);

// 8.通过extClassLoader获取启动类加载器(父加载器)
ClassLoader bootClassLoader = extClassLoader.getParent();

// 9.由于启动类加载器是C语言开发的,在Java代码中无法实例化对象,所以只能返回null值
System.out.println("bootClassLoader = " + bootClassLoader);

双亲委派机制

images

  • 当我们需要加载任何一个范围内的类时,首先找到这个范围对应的类加载器
  • 但是当前这个类加载器不是马上开始查找
  • 当前类加载器会将任务交给上一级类加载器
  • 上一级类加载器继续上交任务,一直到最顶级的启动类加载器
  • 启动类加载器开始在自己负责的范围内查找
  • 如果能找到,则直接开始加载
  • 如果找不到,则交给下一级的类加载器继续查找
  • 一直到应用程序类加载器
  • 如果应用程序类加载器同样找不到要加载的类,那么会抛出ClassNotFoundException异常

 

验证双亲委派机制

实验1

  • 第一步:在与JDK无关的目录下创建Hello.java
public class Hello {
	
	public static void main(String[] args){
		System.out.println("Hello  world");
	}
	
}
  • 第二步:编译Hello.java
  • 第三步:将Hello.class文件移动到$JAVA_HOME/jre/classes目录下
  • 第四步:修改Hello.java
public class Hello {
	
	public static void main(String[] args){
		System.out.println("goodbye");
	}
	
}
  • 第五步:编译Hello.java
  • 第六步:将Hello.class文件移动到$JAVA_HOME/jre/lib/ext/classes目录下
  • 第七步:修改Hello.java
public class Hello {
	
	public static void main(String[] args){
		System.out.println("Tom like jerry");
	}
	
}
  • 第八步:编译Hello.java
  • 第九步:使用java命令运行Hello类,发现打印结果是:Hello  world
    • 说明Hello这个类是被启动类加载器找到的,找到以后就不查找其他位置了
  • 第十步:删除$JAVA_HOME/jre/classes目录
  • 第十一步:使用java命令运行Hello类,发现打印结果是:goodbye
    • 说明Hello这个类是被扩展类加载器找到的,找到以后就不查找其他位置了
  • 第十二步:删除$JAVA_HOME/jre/lib/ext/classes目录
  • 第十三步:使用java命令运行Hello类,发现打印结果是:Tom like jerry
    • 说明Hello这个类是被应用程序类加载器找到的

实验2

  • 第一步:创建假的String类
package java.lang;

public class String {

    public String() {
        System.out.println("嘿嘿,其实我是假的!");
    }

}
  • 第二步:编写测试程序类
    @Test
    public void testLoadString() {

        // 目标:测试不同范围内全类名相同的两个类JVM如何加装
        // 1.创建String对象
        java.lang.String testInstance = new java.lang.String();

        // 2.获取String对象的类加载器
        ClassLoader classLoader = testInstance.getClass().getClassLoader();
        System.out.println(classLoader);
    }
  • 第三步:查看运行结果是null
    • 假的String类并没有被创建对象,由于双亲委派机制,启动类加载器加载了真正的String类

双亲委派机制的好处

  1. 避免类的重复加载:父加载器加载了一个类,就不必让子加载器再去查找了。同时也保证了在整个 JVM 范围内全类名是类的唯一标识。
  2. 安全机制:避免恶意替换 JRE 定义的核心 API

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文阅读】基于深度学习的时序异常检测——TimesNet

系列文章链接 参考数据集讲解:数据基础:多维时序数据集简介 论文一:2022 Anomaly Transformer:异常分数预测 论文二:2022 TransAD:异常分数预测 论文三:2023 TimesNet:基于卷积的多任…

《乡村振兴战略下传统村落文化旅游设计》浙江新华书店已售罄!

《乡村振兴战略下传统村落文化旅游设计》浙江新华书店已售罄!

CTF Stegano练习之隐写初探

今天要介绍的是CTF练习中的Stegano隐写题型 。做隐写题的时候,工具是很重要的,接下来介绍一些工具。 1、TrID TrID是一款根据文件二进制数据特征进行判断的文件类型识别工具。虽然也有类似的文件类型识别工具,但是大多数都是使用硬编码的识…

11个点告诉你 如何用Docker+jenkins 运行 python 自动化

一、实现思路 在 Linux 服务器安装 docker 创建 jenkins 容器 根据自动化项目依赖包构建 python 镜像(构建自动化 python 环境) 运行新的 python 容器,执行 jenkins 从仓库中拉下来的自动化项目 执行完成之后删除容器 二、环境准备 Linux 服务器一台(我的是 C…

面向数据科学家和分析师的统计基础

推荐:使用 NSDT场景编辑器助你快速搭建可编辑的3D应用场景 “统计学是科学的语法。 卡尔皮尔逊 统计学在数据科学和数据分析中的重要性不容低估。统计提供了查找结构和提供更深入数据见解的工具和方法。统计学和数学都喜欢事实,讨厌猜测。了解这两个重要…

网络安全(黑客)零基础入门

导语 什么是 Web 安全?我又该如何入门学习它呢?学习过程中又应注意哪些问题呢?... 或许你的心中有着这样的疑问、不过别着急,本文会为你一一解答这些问题。 正文 定义 Web 安全,顾名思义便是由保障 Web 应用能够持续…

微信私域更好玩了

之前分享过,“小绿书”“公众号文章转音频”等内测中或悄悄已升级的功能。 其实,微信还在内测很多新功能,只是没公开 今天,小编又发现新升级 就是『附近』功能 增加了一个本地生活的入口,这里面是短视频和图文 展示…

IoTDB 1.x 开启外部访问

对于部署的IoTDB数据库,如果需要局域网内其他设备进行访问的处理。 1、防火墙开放端口 无论windows还是liunx都需要你将6667默认的端口加入防火墙中,否则肯定是无法访问端口 2、修改配置文件 对conf/iotdb-datanode.properties文件中的 修改为本机的…

Oracle DB 安全性 : TDE HSM TCPS Wallet Imperva

• 配置口令文件以使用区分大小写的口令 • 对表空间进行加密 • 配置对网络服务的细粒度访问 TCPS 安全口令支持 Oracle Database 11g中的口令: • 区分大小写 • 包含更多的字符 • 使用更安全的散列算法 • 在散列算法中使用salt 用户名仍是Oracle 标识…

Python入门02

0目录 1.容器操作(序列操作) 2.函数 3.模块 1.容器操作(序列操作) 列表的基本操作 定义一个列表[] 访问列表(打印或者通过下标和索引) 新增元素 Append(在末尾) 指定位置新增元素 Insert 删除&…

【算法篇C++实现】算法的时间、空间复杂度

文章目录 🚀一、算法的概念🚀二、算法的特征1.可行性2.确定性3.有穷性4.输入5.输出 🚀三、算法的评价1.正确性2.可读性3.健壮性 🚀四、算法的复杂度⛳(一)时间复杂度1、时间复杂度的概念2、大O的渐进表示法…

多线程案例(4)-线程池

文章目录 多线程案例四四、线程池 大家好,我是晓星航。今天为大家带来的是 多线程案例-线程池 相关的讲解!😀 多线程案例四 四、线程池 线程池是什么 虽然创建线程 / 销毁线程 的开销 想象这么一个场景: 在学校附近新开了一家…

MyBatis查询数据库之四(动态SQL -- if、trim、where、set、foreach 标签)

目录 动态SQL 一、 标签 二、标签 三、标签 四、标签 五、标签 动态SQL 动态 SQL 是 MyBatis 的强大特性之一,使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。…

【脚踢数据结构】链表(2)

(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,Linux基础,ARM开发板,软件配置等领域博主🌍快上🚘,一起学习,让我们成为一个强大的攻城狮!送给自己和读者的一句鸡汤🤔&…

Effective Java笔记(29)优先考虑泛型

一般来说 ,将集合声 明参数化,以及使用 JDK 所提供的泛型方法,这些都不太困难 。编写自己的泛型会比较困难一些,但是值得花些时间去学习如何编写 。 以简单的(玩具)堆校实现为例 : // Object -…

【OpenGauss源码学习 —— 执行算子(SeqScan算子)】

执行算子(SeqScan算子) 执行算子概述扫描算子SeqScan算子ExecInitSeqScan函数InitScanRelation函数ExecSeqScan函数 总结 声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵…

IoTDB1.X windows运行失败问题的处理

在windows运行 IoTDB1.x时 会出现如图所示的问题 为什么会出现这样的问题?java没有安装还是未调用成功,我是JAVA8~11~17各种更换都未能解决问题,最后对其bat文件进行查看,发现在conf\datanode-env.bat、conf\confignode-env.bat这…

拆解与重构:慕云游首页组件化设计

目录 前言1 项目准备1.1 创建项目目录1.2 搭建项目开发环境 2 项目组件化2.1 在当前环境启动原有项目2.2 顶部组件2.3 幻灯片组件2.3.1 功能实现2.3.2 加载中组件2.3.3 结构和样式2.3.4 使用Ajax获取数据 2.4 机酒自由行组件2.5 拆分余下的css文件 3 项目完善4 源码 前言 在现代…

C 语言的逻辑运算符

C 语言的逻辑运算符包括三种: 逻辑运算符可以将两个关系表达式连接起来. Suppose exp1 and exp2 are two simple relational expressions, such as cat > rat and debt 1000 . Then you can state the following: ■ exp1 && exp2 is true only if bo…

用库造一个list的轮子 【C++】

文章目录 list的模拟实现默认成员函数构造函数拷贝构造函数赋值运算符重载析构函数 迭代器迭代器为什么要存在?const_iteratorbegin和end inserterasepush_back && pop_backpush_front &&pop_frontswap 完整代码 list的模拟实现 默认成员函数 构造…