小研究 - JVM 的类装载机制

news2024/9/25 7:25:49

本文通过对一个类装载实例的分析,阐明了 Java虚拟机的类装载的代理机制和由此定义的命名空间,指出了类装载机制在容器/组件/抽象框架结构中的作用。

目录

1  引言

2  实例

3  分析

3.1  类装载的代理机制

3.2  Java的命名空间

3.3  解决问题

4  应用

4.1  容器组件抽象框架

4.2  类装载器和容器组件抽象框架

5  结论


1  引言

Java虚拟机 JVM)的类装载就是指将包含在类文件中的字节码装载到JVM中,并使其成为JVM一部分的过程口。JVM 的类动态装载技术能够在运行时刻动态地加载或者替换系统的某些功能模块,而不影响系统其他功能模块的正常运行。类的动态加载是 JVM 的一项非常重要的技术,是许多企业 Java技术的基础,应用它可以以相对简单、灵活的形式来构建复杂的企业级应用。类的动态加载技术和具有部分类似功能的动态链接库技术相比,具有灵活、面向对象、平台独立等优点。

2  实例

下面是有关 JVM 的类动态装载技术的一个例子,包括:一个类装载器(CL. java)、一个接口(A. java)和一个实现类B. java)。代码的主要部分如下:

/CL.java
publicclassCLextendsClassLoader{
 protectedClassfindClass)Stringname)throwsClassNot-
FoundException{
byte[]b=loadClassData(name);
returndefineClass(name,b,0,b.length);
 }
 privatebyte[]loadClassData(Stringname)throwsClass-
NotFoundException{
 //获取并返回指定类的字节码…
 }
 publicstaticvoidmain(Stringargs[])throwsException{
Classb=newCL().loadClass(arg[0]);
Aa=(A)b.newInstance();//59行
a.f()
 }
}
//A.java
publicinterfaceA{
 publicvoidf();
}
//B.java
publicclassBimplementsA {
 publicvoidf(){
System.out.println("B.f()");
 }
}

其中,实现类B不在类路径(CLASSPATH)中,并且是到运行时才给出的。用 JDK 1.2以上版本的 Java编译器编译以上代码,然后运行:

>javaCLB

如果如下:

b.f()

可见,类装载器CL已经成功地将类B装载到JVM中。JVM也成功地激活了类 B中的方法。在这个过程中,Java的类装载子系统实现上完成了三个步骤:装载、链接和初始化。其中链接又可以分为校验(Verification)、准备Prepara tion)和决定Resolution)三步。除决定外,其他步骤是严格按顺序完成的。各步骤的主要工作如下:

装载:查找和导入类或接口的二进制数据。

链接:执行下面的校验、准备和决定步骤,其中决定步骤是可选的。

校验:检查导入类或接口的二进制数据的正确性。

准备:给类的静态变量分配并初始化存储空间。

决定:将符号引用转成直接引用。

初始化:激活类的静态变量的初始化Java代码和静态Java代码块。

JVM 的类装载子系统的更多介绍可参见资料。

根据Java2的扩展机制3,将CL. class文件打包成clja文件,并将cl jar文件放在Java执行环境的扩展目录通常为<JAVA-HOME> /jre/lib/ext具体可查看运行时环境变量java ext dirs值)中。

当再次执行以上程序:

> java CL B

结果如下:(第59行已在代码中标出)

Exception in thread "main" java.lang.NoClassDef-
FoundError:A
atCL.main(CL.java:59)

抛出的例外指明类A没有找到,可是类A确实在类路径(CLASSPATH)中。而在将cl jar文件放在Java执行环境的扩展目录之前,程序运行正确。那么,从类路径CLASSPATH装载类和从Java扩展目录装载类到底有什么不同呢?

3  分析

3.1  类装载的代理机制

Java2的类装载模型是一种代理(delegation,有人译成委托)模型3.当JVM要求类装载器L1装载一个类时,L1首先将这个类装载请求转发给他的父装载器。只有当父装载器没有装载并无法装载这个类时,L1才获得装载这个类的机会。这样,所有类装载器的代理关系构成了一棵树。树的根是类的根装载器(bootstrap Class Loader),在JVM中他以"null表示。除根装载器以外的类装载器有且仅有一个父装载器。在创建一个装载器时,如果没有显式地给出父装载器,那么JVM将默认系统装载器为其父装载器。Java2的基本的类装载器代理结构如图1所示。

根Bootstrap)装载器:从sun boot class path装载运行时类库的核心代码;是JVM的一部分,没有父装载器。

扩展(Extension)装载器:从 java ext dirs 扩展目录)中装载代码;父装载器为根装载器;用纯Java代码实现。

系统(System orApplication)装载器:从java class path(CLASSPATH环境变量)装载代码;父装载器为扩展装载器;用纯Java代码实现;是用户自定义类装载器的缺省父装载器。

小应用程序(Applet)装载器:从用户指定的网络上的特定目录装载小应用程序代码;父装载器为系统装载器。

一个好的类装载器应该满足以下二个性质2

1)对于相同的类名,类装载器应该返回同一个类对象。

2)如果类装载器 L1将装载类 C的请求转给类装载器L2,那么对于以下的类或接口 T,L1和 L2应该返回同一个类对象:

aT为 C的直接超类;

b)T 为 C的直接超接口;

cT为 C的成员变量的类型;

d)T为C的成员函数或构建器的参数类型;

e)T为C的成员函数的返回类型

每个已经装载到JVM中的类都隐含有装载他的类装载器的信息。类方法getC lassLoader可以得到装载这个类的类装载器。已经装载到JVM中的类不能更改他的类装载器。一个类装载器认识的类包括他的父装载器认识的类和他自己装载的类。一个类装载器认识的类是他自己装载的类的超集。

Java2中的类的装载过程是代理装载的过程。比如:W el浏览器中的JVM需要装载一个小应用程序SampleApplet JVM调用小应用程序装载器ACL来完成装载。ACL首先请求他的父装载器,即系统装载器装载SampleApplet由于SampleA pplet不在系统装载器的装载路径中,所以系统装载器没有找到这个类,也就没有装载成功。接着ACL自己装载SampleApplet ACL通过网络成功地找到了SampleApplet class文件并将他导入到了JVM中。在装载过程中,JVM发现SampleApplet是从超类java applet Applet继承的。所以JVM再次调用ACL来装载java applet Applet类。ACL又再次按上面的顺序装载Applet类,结果ACL发现他的父装载器已经装载了这个类,所以ACL就直接将这个已经装载的类返回给了JVM,完成了Applet类的装载。接下来, Applet类的超类也一样处理。最后, SampleA pplet及所有有关的类都装载到了 JVM 中。

3.2  Java的命名空间

从类装载的代理机制可以看出:在Java中,不同的类装载器定义了不同的命名空间。并且这些由类装载器定义的命名空间会有部分重叠,这保证了面向对象技术的一些重要特性,比如继承和多态的实现同。可以想象,如果没有这种父装载器首先获得装载权利的代理机制,而是所有的类装载器都各自装载,那么各个类装载器装载到JVM中的类都相互无关。JVM 本身的一些基本的类,如java lang. Object类在每个类装载器的命名空间中都得保留一个副本。并且更为严重的是,这些不同命名空间中的类被完全隔离开来了,他们之间不能进行任何形式的交互,也就不存在继承、多态等一些面象对象的关键特性。

3.3  解决问题

理解了类装载的代理机制和Java的命名空间后,再看本文前面的实例中抛出的例外,就很显然了。将cl jar文件放在Java执行环境的扩展目录以前,从命令行运行程序 CL,JVM首先调用系统类装载器装载CL类,由于系统装载器的父装载器是扩展类装载器,所以扩展类装载器先于系统类装载器获得装载CL的机会,可是扩展装载器在他的装载目录中没有找到 CL类的定义,接着,系统类装载器获得装载 CL类的机会,由于CL类在系统路径中,所以系统类装载器最终装载了类CL。类 A在类CL中被引用,其装载过程和类CL的装载过程完全一致。

从 java命名空间的划分来看,在将 cl jar文件放在 Java执行环境的扩展目录以前和以后。类CL和类A在Java的命名空间的位置如图2所示。

对类装载的代理机制和 Java的命名空间的理解能够加深对Java语言的认识。比如:有时会听到这样的表述:“一个Java类可由它的全名包名+.+类名)唯一标识”。这种表述只有在同一命名空间中是正确的,如果要在所有命名空间中都成立,须如下表述:“一个 Java类可由它的全名包名+.+类名)和它的类装载器唯一标识”。

4  应用

4.1  容器组件抽象框架

抽象框架是容器和由容器管理的组件之间的某种约定。通常,容器为组件提供了一些公共服务,如激活、生命周期、持久性、安全、事务等回。比如:一个Java兼容的WEB浏览器给小应用程序提供了激活和生命周期服务。这时,java applet包就是抽象框架,用户写的特定的小应用程序就是组件,浏览器就是容器。注意:java applet包中的Applet类是抽象的。容器和组件间的接口的定义通常是抽象的,这也是为什么称抽象框架的原因。

4.2  类装载器和容器组件抽象框架

为了实现容器组件抽象框架这种架构,关键的一点是要确保定义抽象框架的抽象类由唯一的类装载器装载,并且对所有需要引用抽象框架的抽象类的类装载器可见。这样就保证了容器中引用的抽象框架和组件中引用的抽象框架是同一个抽象框架,也满足了面向对象的继承、多态特性。通常,定义抽象框架的抽象类由实现他的组件的类装载器的父装载器来装载。如在Servlet兼容的WEB服务器中,将装载Servle抽象框架类的某个核心类装载器作为所有 Servlet类的父装载器。容器 /组件 /抽象框架和类装载器的关系如图3所示。图3可以看出,类装载器的代理机制从逻辑上保证了容器/组件抽象框架这三者关系的正确实现。

5  结论

类的动态装载机制是 JVM 的一项核心技术,也是容易被忽视而引起很多误解的地方。只有深刻地理解了类装载的代理机制以及由此引出的Java命名空间,才能更加灵活、可靠、有效地构建复杂的企业级应用。

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

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

相关文章

全栈之前端 | 1.CSS3必备基础知识学习

关注回复【学习交流群】加入【安全开发运维】答疑交流群 请朋友们【多多点击文中的广告】&#xff0c;支持作者更新更多文章。 目录: 0x00 前言简述 描述: 前面跟随着WeiyiGeeker作者【全栈工程师修炼指南】公众号一起学习了前端基础的知识以及HTML标签、属性、事件、字符集系列…

寻找注册配置中心最佳评测官,赢取丰厚奖品 | 测评开启,开发者请速速集结

评测前请点击文末链接&#xff0c;领取 MSE-Nacos 免费试用&#xff0c;再启动评测。 注册配置中心 MSE-Nacos (以下简称 MSE-Nacos)&#xff0c;即 Nacos 的企业版&#xff0c;开箱即用的 Nacos 云服务&#xff0c;对 Nacos 内核进行企业级稳定性加固&#xff0c;故障自动检测…

统计学补充概念-13-逻辑回归

概念 逻辑回归&#xff08;Logistic Regression&#xff09;实际上是一种用于解决分类问题的统计学习方法&#xff0c;尽管其名称中带有"回归"一词&#xff0c;但它主要用于处理分类任务。逻辑回归用于预测一个事件发生的概率&#xff0c;并将其映射到一个特定的输出…

js的this指向问题

代码一&#xff1a; 这段代码定义了run函数、obj对象&#xff0c;然后我们把run函数作为obj的方法。 function run(){console.log(this);}let obj{a:1,b:2};obj.runrun;obj.run(); 那么我们调用obj的run方法&#xff0c;那么这个方法打印的this指向obj。 分析&#xff1a;即…

第十三课 宾语从句

文章目录 前言一、宾语从句1、主语及物动词宾语从句2、主语双宾动词间接宾语直接宾语3、主语特定及物动词宾语从句&#xff08;作宾语&#xff09;宾补4、主语be某些形容词宾语从句5、动词不定式后面的宾语从句6、动名词后面的宾语从句7、介词后面的宾语从句9、间接引语 前言 一…

基于LOF算法的异常值检测

目录 LOF算法简介Sklearn官网LOF算法应用实例1Sklearn官网LOF算法应用实例2基于LOF算法鸢尾花数据集异常值检测读取数据构造数据可视化&#xff0c;画出可疑异常点LOF算法 LOF算法简介 LOF异常检测算法是一种基于密度的异常检测算法&#xff0c;基于密度的异常检测算法主要思想…

Centos7安装ZK-UI管理界面安装|Maven|Git|

一: JDK1.8安装 参考: Centos7卸载|安装JDK1.8|Xshell7批量控制多个终端 二&#xff1a;Maven安装 2.1&#xff1a;下载maven安装包 maven 下载地址&#xff1a;https://mirror.bit.edu.cn/apache/maven/maven-3/ [rootwww ~]# mkdir -p /usr/local/maven [rootwww ~]# …

【C/C++】多态的概念 | 虚函数 | 虚函数指针

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

Linux操作系统--vi/vim编辑器

1.Vi/Vim简介 Vi 是 Unix 操作系统和类 Unix 操作系统中最通用的文本编辑器。 VIM 编辑器是从 VI 发展出来的一个性能更强大的文本编辑器。可以主动的以字体颜色辨别语法的正确性,方便程序设计。VIM 与 VI 编辑器完全兼容。这里简单的理解为如果你需要使用指令取操作Linux系…

【LeetCode-中等题】142. 环形链表 II

文章目录 题目方法一&#xff1a;哈希表set去重方法二&#xff1a;快慢指针 题目 方法一&#xff1a;哈希表set去重 思路&#xff1a;我们遍历链表中的每个节点&#xff0c;并将它记录下来&#xff1b;一旦遇到了此前遍历过的节点&#xff0c;就可以判定链表中存在环。借助哈希…

nonlocal关键字声明

nonlocal关键字声明 作用 使得内层函数可以使用/修改外层函数的变量 值得注意的是&#xff0c;在未使用nonlocal声明时 对于外层函数中的可变对象&#xff0c;内层函数即可访问&#xff0c;也可以修改 def outer():x, y [1], [2]def inner(z):x.append(1)print(x)print(z)r…

英特尔oneAPI人工智能黑客松 - 坚果识别实战

写在前面&#xff1a;博主是一只经过实战开发历练后投身培训事业的“小山猪”&#xff0c;昵称取自动画片《狮子王》中的“彭彭”&#xff0c;总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域&#xff0c;如今终有小成…

Ubuntu断电重启后黑屏左上角光标闪烁,分辨率低解决办法,ubuntu系统display只有4:3 怎么办?太卡

这个问题主要是显卡驱动问题&#xff0c;按照步骤更新显卡驱动 1&#xff0c;选择metapackage 并且选择proprietary版本&#xff0c;选择版本号选择最新的版本。 2&#xff0c;具体步骤参考 前言 笔者在安装显卡驱动时并未遇到问题&#xff0c;主要是后续屏幕亮度无法调节&…

qt在线包下载安装出错 无法检索远程树

我的问题好像是在安装Qt5.15.2出现的。 我的情况是由于网络问题问题&#xff0c;设置开启了本机的代理之后&#xff0c;就可以正常下载了。

STM32F103 USB OTA升级APP (二)

接上一篇STM32F103 USB OTA升级BootLoader (一)&#xff1a;跳转链接 修改程序启动地址和Flash大小 修改main.c代码 #include "main.h" #include "usart.h" #include "usb_device.h" #include "gpio.h" #include "Update.h&quo…

空时自适应处理用于机载雷达——空时处理基础知识(Matla代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

基于STM32CUBEMX驱动TMOS模块STHS34PF80(6)----获取状态数据

基于STM32CUBEMX驱动TMOS模块STHS34PF80----6.获取状态数据 概述视频教学样品申请参考Demo参考程序获取数据获取数据标志位使用数据准备就绪信号嵌入式智能数字算法的输出数据主程序 概述 STHS34PF80传感器项目种修改 Arduino 脚本&#xff0c;重新移植到STM32的MCU中。 该项目…

PAT 1127 ZigZagging on a Tree

个人学习记录&#xff0c;代码难免不尽人意。 Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences. And it is a simple standard routine t…

Experience Design(XD)软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 Experience Design&#xff08;XD&#xff09;是Adobe公司开发的一款用户体验设计工具&#xff0c;广泛应用于网页设计、移动应用设计、交互设计等领域。以下是XD软件的主要特点和功能&#xff1a; 界面设计&#xff1a;XD提供…

android2022配置opencv4android480

1&#xff0c;安装android studio2022。 2&#xff0c;下载OPENCV4ANDROID&#xff0c;解压到任意盘中。 3&#xff0c;File->New->New Project&#xff0c;选择Empty Views Activity。再选择语言&#xff0c;本文选择JAVA。 4&#xff0c;File->New->Import Modu…