Java类加载

Java类加载机制是Java虚拟机(JVM)的一个核心组成部分,它负责将Java类从不同的数据源(如本地文件系统、网络等)加载到JVM中,并为之生成对应的java.lang.Class对象。理解Java类加载机制对于深入理解Java运行时的行为、解决类加载相关的问题以及进行高级框架开发都具有重要意义。

类加载的生命周期

在这里插入图片描述

// 加载
硬盘查找并通过IO读入字节码文件(Java编译过的.class文件),这里是懒加载,只有使用时才会加载(通过类加载器),加载会在内存中(JVM的元空间)生成一个代表这个类的Class对象.
// 验证
校验字节码文件的正确性.比如格式、jdk版本号等.
// 准备
为类的静态变量分配内存,并将其初始化为默认值(例如ingt默认值0)
// 解析
将类中的符号引用转换为直接引用。
这里的'符号引用'指的是类文件常量池中的各种引用,它们以一种抽象的方式引用其他类、接口、字段和方法,而这些引用在类文件中并不直接指向目标的内存地址。当类被加载解析时需要将这些'符号引用'转化为'直接引用'.
// 初始化
初始化阶段是执行类构造器<clinit>()方法的过程。这个方法由编译器自动合成,包含了类变量的赋值操作和静态代码块中的语句。
// 使用
在完成了加载、链接(验证、准备、解析)和初始化之后,类就可以被程序使用了,比如创建类的实例、访问类的静态变量和调用类的静态方法等。
// 卸载
类在长时间没有被使用且没有任何引用时,JVM会考虑将其卸载,释放掉占用的资源.

类加载器

Java虚拟机通过类加载器来实现类的加载。Java中的类加载器通常分为以下几种:

// 启动类加载器(Bootstrap ClassLoader)
它是虚拟机自带的类加载器,负责加载JAVA_HOME/lib目录中的类库。
// 扩展类加载器(Extension ClassLoader)
它负责加载JAVA_HOME/lib/ext目录中的类库。
// 应用程序类加载器(Application ClassLoader)
它负责加载用户类路径(Classpath)上所指定的类库。
// 自定义类加载器
用户还可以通过继承java.lang.ClassLoader类的方式来创建自定义的类加载器。

双亲委派机制

双亲委派机制(Parent Delegation Model)是Java类加载器(ClassLoader)采用的一种类加载机制。在这种机制下,类加载器在尝试加载一个类时,会先委托给其父加载器进行加载,每一级加载器都是如此,直到顶层的启动类加载器(Bootstrap ClassLoader)。只有当父加载器无法完成这个加载请求(它在自己的搜索范围内没有找到所需的类)时,子加载器才会尝试自己去加载这个类。

在这里插入图片描述

// 加载user.class的过程
1.首先AppClassLoader会在自己的缓存中进行判断,user.class是否已经被加载过,有就直接返回,若没有则会委托它的父类加载器ExtClassLoader.
2.ExtClassLoader也是同样的先在自己的缓存里判断是否加载过user.class,
有就直接返回,若没有则会委托它的父类加载器BootStrapClassLoader.
3.BootStrapClassLoader也是判断缓存中是否有,没有就加载,没有加载到就交给
ExtClassLoader来加载,如果还没有就轮到AppClassLoader加载.
4.最终由AppClassLoader加载user.class.
双亲委派机制的优点

1.避免类的重复加载:由于在顶层的启动类加载器开始往下查找,因此类只会被加载一次,避免了在JVM中类的多份副本。
2.保护程序安全:通过这种机制可以确保Java核心库的类型安全,防止核心API被随意篡改。

自定义类加载器

自定义类加载器需要继承 java.lang.ClassLoader 类,这个类有两个核心方法

// loadClass() 实现了双亲委派机制
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// If still not found, then invoke findClass in order// to find the class.long t1 = System.nanoTime();c = findClass(name);// this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}// findClass()默认实现是空方法
// 所以我们自定义类加载器主要是重写findClass方法。protected Class<?> findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);}

注:自定义类加载器默认父加载器是AppClassLoader。

打破双亲委派机制

打破双亲委派机制通常是指在自定义类加载器时,改变类加载器默认的行为,即不完全遵循双亲委派模型。在某些特定场景下,这样做是有必要的,例如Tomcat部署多个应用程序,每个程序可能依赖第三方框架的不同版本.

例子

要打破双亲委派机制,可以通过覆盖ClassLoader类的loadClass(String name, boolean resolve)方法来实现。

public class CustomClassLoader extends ClassLoader {@Overridepublic Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {// 首先,检查请求的类是否已经被加载Class<?> clazz = findLoadedClass(name);if (clazz == null) {try {// 尝试用自定义的方式加载类clazz = findClass(name);} catch (ClassNotFoundException e) {// 如果自定义方式失败,调用父类加载器尝试加载clazz = super.loadClass(name, resolve);}}if (resolve) {resolveClass(clazz);}return clazz;}
}

在这个例子中,CustomClassLoader首先尝试通过自定义的方式(findClass方法)来加载类,只有在失败时才回退到调用父类加载器的loadClass方法。这种方式实际上是先尝试子类加载器,然后才是父类加载器,与双亲委派模型的顺序相反。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【实战】一、Jest 前端自动化测试框架基础入门(二) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(二)

文章目录 一、Jest 前端自动化测试框架基础入门5.Jest 中的匹配器toBe 匹配器toEqual匹配器toBeNull匹配器toBeUndefined匹配器和toBeDefined匹配器toBeTruthy匹配器toBeFalsy匹配器数字相关的匹配器字符串相关的匹配器数组相关的匹配器异常情况的匹配器 6.Jest 命令行工具的使…

Codeforces Round 925 (Div. 3) D. Divisible Pairs (Java)

Codeforces Round 925 (Div. 3) D. Divisible Pairs (Java) 比赛链接&#xff1a;Codeforces Round 925 (Div. 3) D题传送门&#xff1a;D.Divisible Pairs 题目&#xff1a;D.Divisible Pairs 题目描述 输出格式 For each test case, output a single integer — the num…

MATLAB | 情人节画个花瓣venn图?

之前七夕节情人节各种花&#xff0c;相册&#xff0c;爱心啥的都快画够了&#xff0c;今年画个花瓣韦恩图&#xff1f; 花瓣上的数字是仅属于该类的样本数&#xff0c;而中心的数字是属于每一类的样本数 教程部分 0 数据准备 % 给组起名t1 t2 t3...t15 setName compose(t%d,…

区块链互操作协议

1. 引言 Alexei Zamyatin等人2019年论文 SoK: Communication Across Distributed Ledgers。 参考资料 [1] 2019年论文 SoK: Communication Across Distributed Ledgers [2] A list of blockchain-related SoK papers [3] 2021年视频 FC21: SoK: Communica…

Java 基于 SpringBoot 的大药房管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

QT:实现图片选择器

一、效果图 二、用到的类 qApp&#xff1a;可以快速获取到项目目录位置。 QSettings &#xff1a;编写config文件&#xff0c;记录上次打开图片的位置&#xff0c;下次打开图片会从上次的位置查找图片。 QPixmap&#xff1a;用于图片的缩放&#xff0c;防止图片过小&#xff0…

【电路笔记】-并联电感

并联电感 文章目录 并联电感1、概述2、并联电感示例13、互耦并联电感器4、并联电感示例25、并联电感示例36、总结当电感器的两个端子分别连接到另一个或多个电感器的每个端子时,电感器被称为并联连接在一起。 1、概述 所有并联电感器上的压降将是相同的。 然后,并联的电感器…

JavaScript中有哪些不同的数据类型

在 JavaScript 中&#xff0c;数据类型是一种用来表示数据的分类&#xff0c;它决定了我们可以对这个数据类型执行哪些操作。在 JavaScript 中有以下几种不同的数据类型&#xff1a; 基本数据类型 字符串 (String)&#xff1a;表示一组字符&#xff0c;可以使用引号&#xff08…

【python学习篇1】python基本语法

一、第一个python程序 在控制台上面输出“你好 python”。 在venv目录下面&#xff0c;新建一个Main1.python的文件夹。 然后在文件当中使用print函数输出一句命令即可。 然后&#xff0c;在Main.py下面&#xff0c;右键一下&#xff0c;运行Main1.py&#xff1a;即可看到下…

java客运管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java客运管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&#…

比特币突然大涨

作者&#xff1a;秦晋 2月9日&#xff0c;除夕夜&#xff0c;比特币突然大涨&#xff0c;最高涨至48219美元&#xff0c;涨幅超6%。据CNBC报道&#xff0c;本周比特币已经上涨10.76%&#xff0c;创下自12月8日以来的最佳的一周。本周ETH上涨8.46%&#xff0c;成为自1月12日以来…

Acwing---844.走迷宫

走迷宫 1.题目2.基本思想3.代码实现 1.题目 给定一个 nm 的二维整数数组&#xff0c;用来表示一个迷宫&#xff0c;数组中只包含 0 或 1&#xff0c;其中 0 表示可以走的路&#xff0c;1 表示不可通过的墙壁。最初&#xff0c;有 一个人位于左上角 (1,1)处&#xff0c;已知该…