浅谈JVM(三):类加载器和双亲委派

news/2025/3/30 18:00:37/

上一篇:
浅谈JVM(一):Class文件解析
浅谈JVM(二):类加载机制

3.类加载器和双亲委派

在这里插入图片描述

3.1 类加载器

​ 虚拟机规范中将类加载器分成两类:引导类加载器(bootstrap class loader)和自定义加载器(user-defined class loader)。引导类加载器是由虚拟机直接提供的(如HotSpot由C++实现引导类加载器),而自定义加载器是抽象类ClassLoader的子类,由用户实现,这里的用户指虚拟机实现(如HotSpot)或程序开发者。自定义加载器可以加载用户自定义的数据源,例如为了防止反编译,可以将源字节码文件进行加密,再通过自定义类加载器解密后。

​ 在HotSpot中,从JDK1.2到JDK 8版本,系统将类加载器的实现分为三种:启动类加载器、扩展类加载器、应用程序类加载器。绝大多数Java程序都会用到以下三个类加载器:

①启动类加载器(Bootstrap Class Loader):负责加载${JAVA_HOME}\lib目录,或者被-Xbootclasspath参数所指定的路径中存放的,而且是Java虚拟机能够识别的(按照文件名识别,如rt.jar、tools.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机的内存中。BootstrapClassLoader不是一个真实存在的Java类,启动类加载器由虚拟机实现,无法被Java程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给启动类加载器去处理,那直接使用null代替即可。

 public static void main(String[] args) {//输出nullSystem.out.println(ClassLoader.class.getClassLoader());}

②扩展类加载器(Extension Class Loader):这个类加载器是在类sun.misc.LauncherExtClassLoader中以Java代码的形式实现的。它负责加载ExtClassLoader中以Java代码的形式实现的。它负责加载ExtClassLoader中以Java代码的形式实现的。它负责加载{JAVA_HOME}\lib\ext目录中,或者被java.ext.dirs系统变量所指定的路径中所有的类库。用户可以把通用性的类库放在ext目录里,在JDK 9之后这种扩展机制被模块化取代。

import sun.net.spi.nameservice.dns.DNSNameService;/*** @author 专治八阿哥的孟老师*/
public class TestClass01 {public static void main(String[] args) {//输出nullSystem.out.println(ClassLoader.class.getClassLoader());//DNSNameService在${JAVA_HOME}\lib\ext,输出sun.misc.Launcher$ExtClassLoaderSystem.out.println(DNSNameService.class.getClassLoader());}
}

③应用程序类加载器(Application Class Loader):这个类加载器由sun.misc.Launcher$AppClassLoader来实现,也叫做"系统类加载器"。它负责加载用户类路径(classpath)上所有的类库,开发者可以直接在代码中使用这个类加载器。如果应用程序中没有自定义过类加载器,一般情况下这个就是程序中默认的类加载器。

import sun.net.spi.nameservice.dns.DNSNameService;/*** @author 专治八阿哥的孟老师*/
public class TestClass01 {public static void main(String[] args) {//输出nullSystem.out.println(ClassLoader.class.getClassLoader());//DNSNameService在${JAVA_HOME}\lib\ext,输出sun.misc.Launcher$ExtClassLoaderSystem.out.println(DNSNameService.class.getClassLoader());//输出sun.misc.Launcher$AppClassLoaderSystem.out.println(TestClass01.class.getClassLoader());//输出sun.misc.Launcher$AppClassLoaderSystem.out.println(ClassLoader.getSystemClassLoader());}
}

上面提到的ExtClassLoader和AppClassLoader都间接继承了ClassLoader,根据虚拟机规范对类加载器的分类,它们都属于user-defined class loader。此外开发者也可以通过继承ClassLoader实现自己定义的类加载器。

在这里插入图片描述

3.2 双亲委派模型

​ 系统中的各加载器会按照一定的关系相互配合完成类的加载,各类加载器的协作关系被称为"双亲委派模型"(Parents Delegation Model),协作关系如下图所示:

在这里插入图片描述

​ 需要注意的是双亲委派是一种协作关系,不是继承关系,AppClassLoader并不是ExtClassLoader的子类。类加载器中有一个parent属性用于描述"父类加载器"。父类加载器是子类加载器的parent属性,而不是super class,所以应该叫"父|类加载器"而不是"父类|加载器"。

在这里插入图片描述

public static void main(String[] args) {//输出sun.misc.Launcher$AppClassLoaderSystem.out.println(ClassLoader.getSystemClassLoader());//输出sun.misc.Launcher$AppClassLoaderSystem.out.println(ClassLoader.getSystemClassLoader().getParent());//输出nullSystem.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());}

​ 双亲委派的协作关系是:类加载器A加载一个类时,先在自己的缓存中查看该类是否加载过,如果已经加载过,就返回,否则向parent类加载器B询问;如果B已经加载,就返回,否则B再向自己的parent询问,重复此过程直到bootstrap classloader启动类加载器;如果到了启动类加载器还没有完成加载请求,则由A自己尝试加载该类。

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {//检查请求的类是否被加载过Class<?> c = findLoadedClass(name);if (c == null) {try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {//如果父类抛出ClassNotFoundException// 说明父类无法完成加载请求}if (c == null) {             //父类无法加载时,自己加载c = findClass(name);}}if (resolve) {resolveClass(c);}return c;}}

​ 双亲委派模型对于保证Java程序的稳定运行极为重要。

​ 在虚拟机中,对于类的唯一性的认定,并不只是通过类的全限定名,只有类的全限定名一致,且由同一个类加载器加载,才算是相同。即使两个类来自同一个Class文件,处于同一个虚拟机中,只要不是同一个类加载器加载的,它们就被认为是不同的类,包括使用equals()方法、isInstance()方法、isAssignableFrom()方法、instanceof关键字的运算结果都会受到影响。

​ 通过双亲委派模型,可以让类加载器之间产生一种有优先级的层次关系,避免类重复加载,还可以保证系统安全。如java.lang.Object类在rt.jar中,无论使用哪个类加载器加载它,都一定会委托给最顶级的启动类加载器。即使用户自己定义了Object类,系统也不会加载它。

在这里插入图片描述

public static void main(String[] args) throws Exception {ClassLoader loader = new ClassLoader() {private String path = "D:\\workspace\\";@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try (InputStream is = new FileInputStream(path + name.replace(".", "/") + ".class")) {byte[] bytes = new byte[is.available()];is.read(bytes);return defineClass(name, bytes, 0, bytes.length);} catch (IOException e) {throw new ClassNotFoundException(name);}}};Object o = loader.loadClass("java.lang.Object").newInstance();}

​ 上面的代码运行后会发现,即使自定义了类加载器,Object类也是由启动类加载器加载的,我们自定义的类不会被加载。如果要打破双亲委派,可以直接修改上面代码,把方法名findClass改成loadClass,此时代码运行会报错:

在这里插入图片描述

​ 系统类库中的包都是被保护起来的,我们自定义和系统重名的包可以通过编译,但不能正常运行,避免了恶意程序危害系统。

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

相关文章

【Android】手写MakeFile文件(一)

MakeFile概述 C语言中&#xff0c;我们使用visual studio开发软件时候&#xff0c;写程序开始时候都会创建一个project项目文件&#xff0c;然后在文件里面编译 .h 和 .c 的文件。 在Linux中&#xff0c;有一个叫做make的指令&#xff0c;就相当于C语言的IDE&#xff0c;我们…

Java数据结构与算法——拓扑排序

拓扑排序 概念 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序&#xff0c;是将G中所有顶点排成一个线性序列&#xff0c;使得图中任意一对顶点u和v&#xff0c;若边<u,v>∈E(G)&#xff0c;则u在线性序列中出现在v之前。通常&#xff0c;这样的线性序…

设计模式-单例模式-懒汉式饿汉式探讨

文章目录基础概念饿汉式实例懒汉式实例懒汉式实例【互斥锁方式保障线程安全】懒汉式实例【双重检查锁定&#xff08;Double-Checked Locking&#xff09;保障线程安全】大型项目中单例模式实用数据库连接池C语言-单例模式实现线程池C语言单例模式-实现日志管理器C语言单例模式-…

GP03丨宽窄基资金管理增强策略

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 正 文 大家好&#xff0c;今天我们分享股票社群第3期量化策略——ETF资金管理增强策略。 在上一期中&#xff0c;我们分享了基础版ETF轮动&#xff08;结合股票多因子排序逻辑&#xff09;策略&#xf…

免费好用的oa系统有哪些?盘点这几款!

免费好用的oa系统有哪些&#xff1f;盘点这几款&#xff01; 办公自动化&#xff08;OA&#xff09;&#xff0c;英文Office Automation的缩写。它可以通过特定流程或特定环节与日常事务联系在一起&#xff0c;使公文在流转、审批、发布等方面提高效率&#xff0c;实现办公管理…

C++从0到1实战

持续更新中… 1、Windows开发环境的准备 2、第一个C程序 3、C中输出数据 4、C中程序的注释 5、C中变量使用 6、C中常量使用 7、C中标识符的命名 8、C中数据输入 9、C中算术运算 10、C中自增和自减 11、C中赋值运算 12、C11初始化赋值 13、C中关系运算 14、C中逻辑运算 15、C中运…

百度研发效能从度量到数字化蜕变之路

y研发 作者 | 乌拉 导读 企业降本增效的诉求越发强烈&#xff0c;研发效能成为近来极为火爆的话题&#xff0c;本文从效能分析整体思路、实践案例、技术实现介绍了如何从效能度量逐步演变形成基于价值的数字化决策系统的过程&#xff0c;通过本文可以了解到&#xff1a; 1、研…

Android 手机自动化测试工具有哪几种?

一、Android手机自动化测试工具&#xff0c;常用的有这7中&#xff1a; 1、首推Appium&#xff1a; 推荐理由&#xff1a;功能非常强大的移动端自动化测试框架&#xff0c;还免费 下载链接&#xff1a;Appium: Mobile App Automation Made Awesome. Appium是一种被广泛使用的…