11.《深入理解Java虚拟机》类加载器与双亲委派模型

2024-05-23 18:32

本文主要是介绍11.《深入理解Java虚拟机》类加载器与双亲委派模型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2017-1-2 20:20 写了一天的blog和看书,看不下去了,回去健身。明天再写。
2017-1-2 23:00 回到寝室我还是妥协了,还是先把这个写完吧。

类与类加载器

虚拟机设计团队把类的加载阶段中的”通过一个类的全限定名来获取此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为”类加载器”。

类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限定于类加载阶段。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话表达地再简单一点就是:比较两个类是否”相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则即使这两个类来源于同一个.class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,这两个类必定不相等。

上面说的”相等”,包括代表类的.class对象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回结果,也包括使用instanceof关键字做对象所属关系判定等情况。

下面给出了一个示例显示不同的类加载器对instanceof关键字运算结果的影响:

package JVM;import java.io.IOException;
import java.io.InputStream;/*** Created by louyuting on 17/1/2.*/
public class ClassLoaderTest {public static void main(String[] args) throws Exception{ClassLoader myLoader = new ClassLoader() {@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {try {String fileName = name.substring(name.lastIndexOf(".")+1)+".class";InputStream is = getClass().getResourceAsStream(fileName);if(is == null){return super.loadClass(name);}byte[] b = new byte[is.available()];is.read(b);return defineClass(name, b, 0, b.length);} catch (IOException e) {throw new ClassNotFoundException(name);}}};Object obj = myLoader.loadClass("JVM.ClassLoaderTest").newInstance();System.out.println(obj.getClass());System.out.print(obj instanceof JVM.ClassLoaderTest);}
}

上述代码的运行结果是:
运行结果

代码里面构造了一个简单的类加载器,加载同一路径下面的class文件。我使用我自己定义的类加载器去加载JVM.ClassLoaderTest这个类,并实例化该对象。从输出结果可知,该类确实是JVM.ClassLoaderTest实例化出来的对象。但是从第二个false可知,该对象与类JVM.ClassLoaderTest做类型检查返回了false,这是因为虚拟机中存在了两个JVM.ClassLoaderTest类,一个是我自己定义的类加载器加载的,一个是系统应用程序类加载器加载的。虽然来自同一个class文件但是依然是两个独立的类,做对象所属类型检查时结果自然是false。

双亲委派模型

从虚拟机角度看只存在两种类型的类加载器:
1. 一种是启动类加载器(BootStrap ClassLoader),这个加载器使用C++实现,是虚拟机自身的一部分。
2. 另外一种就是所有其他类加载器,这些类加载器都是由java语言实现的,独立于虚拟机外部,并且全部继承与java.lang.ClassLoader。

从开发人员角度看可以划分更加细:
类加载器双亲委派模型

1、启动类加载器Bootstrap ClassLoader
之前说过了这是一个嵌在JVM内核中的加载器。它负责加载的是JAVA_HOME/lib下的类库,或则被-Xbootclasspath参数指定的路径中的,并且是虚拟机是别的类库加载到虚拟机内存中。系统类加载器无法被Java程序直接应用

2、扩展类加载器Extension ClassLoader
这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责用于加载JAVA_HOME/lib/ext目录中的,或者被java.ext.dirs系统变量指定所指定的路径中所有类库,开发者可以直接使用扩展类加载器。java.ext.dirs系统变量所指定的路径的可以通过程序来查看
System.out.println(System.getProperty("java.ext.dirs"));
运行结果:
/Users/louyuting/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.7.0_72.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java

3、应用程序类加载器Application ClassLoader
这个类加载器由sun.misc.Launcher$AppClassLoader实现。这个类也一般被称为系统类加载器。

我们的应用程序都是由这3种类加载器互相配合进行加载的,有必要还可以加入自定义的类加载器。

下图展示了类加载器之间的层次关系:
双亲委派模型

这里的类加载器之间的父子关系不是继承关系,而只是层次上的定义。它并不是一个强制性的约束模型,而是Java设计者推荐给开发者的一种类加载器实现方式。

双亲委派模型的工作过程是:
1. 如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此。
2. 所有的加载请求最终都会传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

所以,其实所有的加载请求最终都应该传送到顶层的启动类加载器中。双亲委派模型对于Java程序的稳定运作很重要,因为Java类随着它的加载器一起具备了一种带有优先级的层次关系。例如java.lang.Object,存放于rt.jar中,无论哪一个类加载器要去加载这个类,最终都是由Bootstrap ClassLoader去加载,因此Object类在程序的各种类加载器环境中都是一个类。相反,如果没有双亲委派模型,由各个类自己去加载的话,如果用户自己编写了一个java.lang.Object,并放在CLASSPATH下,那系统中将会出现多个不同的Object类,Java体系中最基础的行为也将无法保证,应用程序也将会变得一片混乱。

这篇关于11.《深入理解Java虚拟机》类加载器与双亲委派模型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/996347

相关文章

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

Spring Boot中的路径变量示例详解

《SpringBoot中的路径变量示例详解》SpringBoot中PathVariable通过@PathVariable注解实现URL参数与方法参数绑定,支持多参数接收、类型转换、可选参数、默认值及... 目录一. 基本用法与参数映射1.路径定义2.参数绑定&nhttp://www.chinasem.cnbs

JAVA中安装多个JDK的方法

《JAVA中安装多个JDK的方法》文章介绍了在Windows系统上安装多个JDK版本的方法,包括下载、安装路径修改、环境变量配置(JAVA_HOME和Path),并说明如何通过调整JAVA_HOME在... 首先去oracle官网下载好两个版本不同的jdk(需要登录Oracle账号,没有可以免费注册)下载完

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建

Java中Integer128陷阱

《Java中Integer128陷阱》本文主要介绍了Java中Integer与int的区别及装箱拆箱机制,重点指出-128至127范围内的Integer值会复用缓存对象,导致==比较结果为true,下... 目录一、Integer和int的联系1.1 Integer和int的区别1.2 Integer和in

SpringSecurity整合redission序列化问题小结(最新整理)

《SpringSecurity整合redission序列化问题小结(最新整理)》文章详解SpringSecurity整合Redisson时的序列化问题,指出需排除官方Jackson依赖,通过自定义反序... 目录1. 前言2. Redission配置2.1 RedissonProperties2.2 Red

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.