我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JVM中ClassLoader类加载器的深入理解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JVM中ClassLoader类加载器的深入理解

JVM的体系结构图

先来看一下JVM的体系结构,如下图:

img

JVM的位置

JVM的位置,如下图:

img

JVM是运行在操作系统之上的,与硬件没有直接的交互,但是可以调用底层的硬件,用JIN(Java本地接口调用底层硬件)

JVM结构图中的class files文件

class files文件,是保存在我们电脑本地的字节码文件,.java文件经过编译之后,就会生成一个.class文件,这个文件就是class files所对应的字节码文件,如下图:

JVM结构图中的类加载器ClassLoader的解释

 类加载器ClassLoader的作用

类加载器只有一个作用,就是负责把我们本地的.class字节码文件,加载到JVM中,以类模板的形式存在于JVM中。

类加载器加载的.class文件也是有要求的,并不是只要是后缀名为.class的文件,都可以被类加载器加载,这个.class文件的必须是.java文件经过编译后得到的字节码文件,也就是指这个.class文件的开头必须要是cafe babe字符单词,它的内容是经过加密后的二进制文件,但是此二进制使用十六进制表示出来的,如下图:

类加载器ClassLoader只负责加载.class文件,但至于他是否可以运行,由JVM中的执行引擎Excution Engine决定的。

img

解释:

Car.class是由.java文件编译得来的.class文件,存在本地磁盘。

ClassLoader:类加载器,负责加载并初始化 类文件,得到真正的Class类,即模板。

Car Class:由Car.class字节码文件,通过ClassLoader加载并且初始化得到,这个Car就是当前类的模板,这个Car Class模板就存在方法区。

car1,car2,car3:是由Car模板经过实例化而得,一个模板可以获得多个实例化对象。

拿car1举例,car1.getClass()可以得到模板Car类,Car.getClassLoader()可得到其装载器。

类加载器的种类

一共有四类。

虚拟机自带的加载器:

启动类加载器,也叫根加载器(BootStrap)。由C++编写,程序中自带的类,存储在 $JAVAHOME/jre/lib/rt.jar中,如object类等

扩展类加载器(Extension),Java编写,在我们看到的类路径中,凡是以Javax开头的,都是拓展包,存储在 $JAVAHOME/jre/lib/ext/*.jar 中,为什么会有扩展包?是因为原本的java包中在功能上,不能满足我们了,所以我们就在原本的java包的基础上扩展出了一些新的功能,而形成的新的包就叫做扩展包。

应用程序类加载器(AppClassLoader),即平时程序中自定义的类 new出来的

用户自定义的加载器:

Java.lang.ClassLoader的子类,用户可以定制类的加载方式,即如果你的程序有特殊的需求,你也可以自定义你的类加载器的加载方式 ,进入ClassLoader的源码,其为抽象类,因此在你定制化开发的时候,需要你定义自己的加载器类来继承ClassLoader抽象类即可,即 MyClassLoader extends ClassLoader

java类的加载机制

首先你需要知道,当java程序需要加载一个类的时候,会去找类加载器,然后找类加载器里面看是否有对应的类模板。

Java的类加载机制,永远是以 根加载器->拓展类加载器->应用程序类加载器 这样的一个顺序进行加载的。什么意思呢?就是如果能在BootStrapClassLoader类加载器的路径下找到对应的类模板,那么就不会再去扩展类加载器ExtensionClassLoader中找对应的类模板,如果能在扩展类加载器ExtensionClassLoader中找到对应的类模板,那么就不会去应用程序类加载器AppClassLoader中找对应的类模板。类加载器的父子级关系,如下图:

img

从上图可以看出根加载器BootStrapClassLoader是扩展类加载器ExtensionClassLoader的父级,扩展类加载器ExtensionClassLoader是应用程序加载器AppClassLoader的父级,如下图:

被某个类加载器加载的类,都会存放到这个类加载器的路径中,当程序需要加载某个类的时候,会先去根加载器BootstrapClassLoader的路径下,寻找是否有这个类的模板,如果没有则会去这个类加载器的下一级,若有,则不会再去下一级寻找了。

利用obj.getClass().getClassLoader()方法,可以找到对应的类模板是存放在哪个类加载器的路径下的,换一个说法,可以让你知道在加载这个类模板所对应的类的字节码文件的时候,是用的哪一个类加载器把这个类的字节码文件加载成类模板的,如下图:

那么问题来了?为什么说Object类是java自带的类呢?java自带的类到底可以在哪里找到呢?java自带的类可以 J A V A H O M E / j r e / l i b / r t . j a r 下 找 到 。 首 先 来 看 一 下 JAVAHOME/jre/lib/rt.jar下找到。首先来看一下 JAVAHOME/jre/lib/rt.jar下找到。首先来看一下JAVAHOME,也即是java的安装目录,如下图:

然后咱来看一下$JAVAHOME/jre/lib/rt.jar中的包(rt其实也即是RunTime的缩写),如下图:

打开rt.jar压缩包,它的目录结构,如下图:

Object类在java/lang包下,如下图:

JVM中的类加载器,根加载器BootStrap,在一开始,就会把rt.jar压缩包中的所有的 类的字节码文件都加载到JVM中,变成类的模板,所以这些java自带的类,对应的类的模板,都会被存放到根加载器BootStrap的路径下面。故当java程序中需要用到java中的自带类的时候,都会去根加载器BootStrap的路径下去寻找类的模板。

双亲委派机制

官方概念:当一个类收到类加载请求后,他不会首先去加载这个类,而是把这个请求委派给父类去完成。每一个层次的类加载器都是如此,因此所有的类加载器请求都是应该传到根加载器中的,只有当其父类加载器自己无法完成这个请求的时候(在他的加载路径下没有找到所需加载的class),子类加载器才会尝试自己去加载。

我的理解翻译:当java程序需要加载一个类的时候,比如要加载java.lang.String类,会首先去根加载器类BootstrapClassLoader的路径下去寻找,如果在根加载器路径下可以找到java.lang.String类,那么就不会再往下寻找java.lang.String类了,因为已经找到了;若在根加载器路径下没有找到java.lang.String类,则会去下一级扩展类加载器ExtensionClassLoader中寻找java.lang.String类,如果在扩展类加载器中找到了java.lang.String类,那么就不会再去下一级类加载器中寻找了;如果没有找到,则会去应用程序类加载器AppClassLoader中去寻找java.lang.String类,如果仍然没有找到会报classNotFoundException异常。

采用双亲委派机制的好处:保证了我们写的代码不会污染到java的源代码,因为只要java的源代码中存在我们即将要加载的类,那么java程序在加载类的时候就会去顶层的根加载器BootstrapClassLoader路径下去寻找类模板,然后把这个类加载。你就比如假设我们自己写一个java.lang包,然后在这个包里面写一个String类,那么如果java源代码中没有java.lang.String这个类,java程序在用到这个类加载的时候,会用到应用程序类加载器AppClassLoader路径下的java.lang.String类,但是,我们都知道java源代码中是有java.lang.String这个类的,也即是在根加载器BootstrapClassLoader路径下有java.lang.String这个类,所以java程序在用到这个类加载它的时候,会加载根加载器BootstrapClassLoader路径下的java.lang.String类,而不会去加载应用程序类加载器AppClassLoader下的java.lang.String类,这样就保证了,我们在java程序的其它地方所用到的java.lang.String类的方法是正确的,怎么个正确法呢?因为啊,假设你是加载的应用程序加载器AppClassLoader路径里的java.lang.String类也即是你自己写的String类,那么在java程序的其它地方如果使用到了源代码java.lang.String类里面的方法该怎么办?这样是不是会出错?这其实也就是,你写的代码污染了人家写的源代码。

双亲委派机制的程序理解,如下图:

沙箱安全机制

通过双亲委派机制,类的加载永远都是从根加载器开始的,如果跟加载器中没有对应的类模板,则会去下一级类加载器中寻找这个类模板,如果有的话则就不会去下一级寻找了。这样就保证你所写的代码不会污染Java自带的源代码,保证了沙箱的安全。

为什么说这样不会污染java自带的源代码呢?因为只要java的源代码中存在我们即将要加载的类,那么java程序在加载类的时候就会去顶层的根加载器BootstrapClassLoader路径下去寻找类模板,然后把这个类加载。你就比如假设我们自己写一个java.lang包,然后在这个包里面写一个String类,那么如果java源代码中没有java.lang.String这个类,java程序在用到这个类加载的时候,会用到应用程序类加载器AppClassLoader路径下的java.lang.String类,但是,我们都知道java源代码中是有java.lang.String这个类的,也即是在根加载器BootstrapClassLoader路径下有java.lang.String这个类,所以java程序在用到这个类加载它的时候,会加载根加载器BootstrapClassLoader路径下的java.lang.String类,而不会去加载应用程序类加载器AppClassLoader下的java.lang.String类,这样就保证了,我们在java程序的其它地方所用到的java.lang.String类的方法是正确的,怎么个正确法呢?因为啊,假设你是加载的应用程序加载器AppClassLoader路径里的java.lang.String类也即是你自己写的String类,那么在java程序的其它地方如果使用到了源代码java.lang.String类里面的方法该怎么办?这样是不是会出错?这其实也就是,你写的代码污染了人家写的源代码。

总结

到此这篇关于JVM中ClassLoader类加载器的文章就介绍到这了,更多相关JVM中ClassLoader类加载器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JVM中ClassLoader类加载器的深入理解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JVM类加载器之ClassLoader的使用详解

类加载器负责读取Java字节代码,并转换成java.lang.Class类的一个实例的代码模块。本文主要和大家聊聊JVM类加载器ClassLoader的使用,需要的可以了解一下
2022-11-13

深入理解java之类加载器

一、类与类加载器类加载器:实现加载阶段的第一步,通过一个类的全限定名来将这个类的二进制字节流加载进jvm。类与类加载器:任意一个类唯一性都是由它本身和加载它的类加载器确定,两个类是否相等在它们是由同一个类加载器加载的前提下。jvm虚拟机中包括两种类加载器:一种
深入理解java之类加载器
2014-12-01

如何深入理解Java虚拟机JVM类加载初始化

如何深入理解Java虚拟机JVM类加载初始化,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1. Classloader的作用,概括来说就是将编译后的class装
2023-06-17

Java类加载器ClassLoader的使用详解

类加载器负责读取Java字节代码,并转换成java.lang.Class类的一个实例的代码模块。本文主要和大家聊聊JVM类加载器ClassLoader的使用,需要的可以了解一下
2022-12-19

深入理解MySQL中的布尔类型

MySQL中的布尔类型是一种非常实用的数据类型,它用于存储逻辑值,只能取两种值:TRUE或FALSE。在MySQL中,布尔类型也被称为BOOL或BOOLEAN,可以用TINYINT(1)来表示。在本文中,我们将深入探讨MySQL中布尔类型的
深入理解MySQL中的布尔类型
2024-03-15

深入浅析java中的继承关系类的加载顺序

这篇文章将为大家详细讲解有关深入浅析java中的继承关系类的加载顺序,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。详解java中继承关系类加载顺序问题实例代码:/** * Created b
2023-05-31

Java中Class类的作用与深入理解

Java中Class类的作用与深入理解 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。JVM利用运行时信息选择相应的方法执行。而保存这些信息的类称为Class。可能容易产
2023-05-31

如何深入了解.NET编译器中CLR加载过程

这期内容当中小编将会给大家带来有关如何深入了解.NET编译器中CLR加载过程,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。以下说明CLR加载过程所使用的工具是VS2005+sos.dll,示例程序代码如下
2023-06-17

深入理解PHP中循环查询子分类的原理

PHP作为一种广泛应用于Web开发的服务器端脚本语言,其强大的特性和灵活的语法使得它成为开发者们的首选。在开发过程中,经常会遇到需要查询子分类的情况,而使用循环来实现这一需求是十分常见的。本文将深入探讨PHP中循环查询子分类的原理,并通过具
深入理解PHP中循环查询子分类的原理
2024-03-07

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录