类加载器

article/2025/9/18 7:11:26

类加载过程

加载->连接->初始化。连接过程又可分为三步:验证->准备->解析

类加载器分类

JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader

  1. 启动类加载器(Bootstrap ClassLoader)此类加载器负责将存放在 <JRE_HOME>\lib 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被 Java 程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给启动类加载器,直接使用 null 代替即可。

  2. 扩展类加载器(Extension ClassLoader)这个类加载器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将 <JAVA_HOME>/lib/ext 或者被 java.ext.dir 系统变量所指定路径中的所有类库加载到内存中,开发者可以直接使用扩展类加载器。

  3. 应用程序类加载器(Application ClassLoader)这个类加载器是由 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,因此一般称为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

双亲委派模型

每一个类都有一个对应它的类加载器。系统中的 ClassLoder 在协同工作的时候会默认使用 双亲委派模型 。

1、在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。

2、加载的时候,首先会把该请求委派该父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时,才由自己来处理。

3、当父类加载器为null时,会使用启动类加载器 BootstrapClassLoader 作为父类加载器。

好处

使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一。

例如 java.lang.Object 存放在 rt.jar 中,如果编写另外一个 java.lang.Object 并放到 ClassPath 中,程序可以编译通过。

由于双亲委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 优先级更高,这是因为 rt.jar 中的 Object 使用的是启动类加载器,而 ClassPath 中的 Object 使用的是应用程序类加载器。rt.jar 中的 Object 优先级更高,那么程序中所有的 Object 都是这个 Object。

保证了Java程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。

如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类。

注意

这个双亲翻译的容易让人误解,一般理解双亲都是父母,这里的双亲表达的是“父母一辈”的人,并不是说真的有一个 Mother ClassLoader 和一个 Father ClassLoader 。另外,类加载器之间的“父子”关系也不是通过继承来体现的,是由“优先级”来决定。官方API文档对这部分的描述如下:

The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.

 源码分析

private final ClassLoader parent; 
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// 首先检查请求的类是否已经被加载过Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {if (parent != null) {//父加载器不为空,调用父加载器loadClass()方法处理c = parent.loadClass(name, false);} else {//父加载器为空,使用启动类加载器 BootstrapClassLoader 加载c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {//父类加载器无法完成加载请求}if (c == null) {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;}}

自定义加载器

除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader

示例:自定义一个NetworkClassLoader,用于加载网络上的class文件

package classloader;import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;/*** 加载网络class的ClassLoader*/
public class NetworkClassLoader extends ClassLoader {private String rootUrl;public NetworkClassLoader(String rootUrl) {this.rootUrl = rootUrl;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {Class clazz = null;//this.findLoadedClass(name); // 父类已加载	//if (clazz == null) {	//检查该类是否已被加载过byte[] classData = getClassData(name);	//根据类的二进制名称,获得该class文件的字节码数组if (classData == null) {throw new ClassNotFoundException();}clazz = defineClass(name, classData, 0, classData.length);	//将class的字节码数组转换成Class类的实例//} return clazz;}private byte[] getClassData(String name) {InputStream is = null;try {String path = classNameToPath(name);URL url = new URL(path);byte[] buff = new byte[1024*4];int len = -1;is = url.openStream();ByteArrayOutputStream baos = new ByteArrayOutputStream();while((len = is.read(buff)) != -1) {baos.write(buff,0,len);}return baos.toByteArray();} catch (Exception e) {e.printStackTrace();} finally {if (is != null) {try {is.close();} catch(IOException e) {e.printStackTrace();}}}return null;}private String classNameToPath(String name) {return rootUrl + "/" + name.replace(".", "/") + ".class";}}

 


http://chatgpt.dhexx.cn/article/Nf21G235.shtml

相关文章

类加载器作用

深入探讨 Java 类加载器 成 富, 软件工程师, IBM 中国软件开发中心 成富任职于 IBM 中国软件开发中心&#xff0c;目前在 Lotus 部门从事 IBM Mashup Center 的开发工作。他毕业于北京大学信息科学技术学院&#xff0c;获得计算机软件与理论专业硕士学位。他的个人网站是 http:…

java中的类加载器

文章目录 前言,一、加载器的作用是什么二、详解类加载器1.不得不说的双亲委派机制2.各个加载器加载的内容3.线程上下文类加载器4.类加载器的庐山真面目 总结 前言, java中一般来说有三种类加载器,分别为: 引导加载器,扩展加载器,应用加载器,还有一个线程上下文类加载器 一、加…

JVM类加载器

文章目录 一、类加载器二、类与类加载器三、双亲委派模型四、破坏双亲委派模型4.1、Tomcat4.1.1、WebApp类加载器4.1.2、Shared类加载器4.1.3、Catalina类加载器4.1.4、Common类加载器4.1.5、Jsp类加载器 4.2、JDBC 一、类加载器 从Java虚拟机的角度来讲&#xff0c;只存在两种…

自定义类加载器

目录 一、为什么要自定义类加载器&#xff1f; 二、常见的场景 三、实现方式 四、自定义类加载器示例 五、Java9新特性 一、为什么要自定义类加载器&#xff1f; 隔离加载类 在某些框架内进行中间件与应用的模块隔离&#xff0c;把类加载到不同的环境。比如&#xff1a;…

类加载器详解(自己实现类加载器)

目录&#xff1a; java虚拟机汇总 class文件结构分析 1).class文件常量池中的常量项结构 2). 常用的属性表的集合类加载过程 1).类加载器的原理以及实现<< 现在位置虚拟机结构分析 1).jdk1.7和1.8版本的方法区构造变化 2).常量池简单区分对象结构分析 1).压缩指针详解gc…

JVM——自定义类加载器

0. 为什么需要自定义类加载器 网上的大部分自定义类加载器文章&#xff0c;几乎都是贴一段实现代码&#xff0c;然后分析一两句自定义ClassLoader的原理。但是我觉得首先得把为什么需要自定义加载器这个问题搞清楚&#xff0c;因为如果不明白它的作用的情况下&#xff0c;还…

JVM - 类加载器

# 类加载器及类加载器执行过程 JDK版本&#xff1a;1.8 # 1、类加载器子系统 下图为类加载子系统&#xff1a; 类加载子系统负责从文件系统或者网络中加载class文件&#xff0c;class文件在文件开头有特定的文件标识&#xff08;CA FE BA BE&#xff09;。Classloader只负责cl…

java的类加载器以及如何自定义类加载器

ClassLoader作用 类加载流程的"加载"阶段是由类加载器完成的。 类加载器结构 结构&#xff1a;BootstrapClassLoader&#xff08;祖父&#xff09;–>ExtClassLoader&#xff08;爷爷&#xff09;–>AppClassLoader(也称为SystemClassLoader)&#xff08;爸…

类加载器(ClassLoader)

一、类加载器&#xff08;ClassLoader&#xff09; 1.1 什么是类加载器 Java的类加载器是Java虚拟机&#xff08;JVM&#xff09;的重要组成部分&#xff0c;它的主要作用是动态地将Java类加载到JVM中&#xff0c;以便在运行时使用这些类。Java类加载器通常是由JVM的实现者提供…

什么是类加载器,类加载器如何分类

一、类加载器 1.什么是类加载器 类加载器&#xff1a;负责将.class文件&#xff08;存储的物理文件&#xff09;加载到内存中 2.类加载时机&#xff1a; ① 创建类的实例&#xff08;对象&#xff09; ② 调用类的实例方法 ③ 访问类或者接口的类变量&#xff0c;或者为该…

深入理解Java虚拟机——再谈类的加载器——第十二章——中篇

深入理解Java虚拟机——Java虚拟机介绍——第一章 深入理解Java虚拟机——类加载子系统——第二章 深入理解Java虚拟机——运行时数据区和本地方法接口——详细篇——第三章 深入理解Java虚拟机——对象的实例化内存布局与访问定位——超级详细篇——第四章 深入理解Java虚拟机…

类加载器详解

类加载器的分类 JVM支持两种类型的类加载器,分别为引导类加载器(BootstrapClassLoader)和自定义类加载器(User-Defined ClassLoader) 从概念上来讲, 自定义类加载器一般指的是程序中由开发人员自定义的一类,类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象类…

Java - 类加载器

文章目录 1. 类加载的过程2. 类加载器的分类2.1 引导类加载器 Bootstrap2.2 扩展类加载器 ExtClassLoader2.3 系统类加载器 AppClassLoader2.4 三者之间的关系2.5 自定义类加载器2.6 注&#xff1a;谁来准备类加载器呢? 3. 双亲委派机制4. ClassLoader抽象类5. URLClassLoader…

DAU 和 MAU

DAU 和 MAU 日活跃用户占月活跃用户的比例越高&#xff0c;表明用户对App的使用粘性越高。 DAU&#xff0c;即&#xff1a;Daily Active User&#xff0c;指日活跃用户数 MAU&#xff0c;即&#xff1a;Monthly Active User&#xff0c;指月活跃用户数。 *例子1&#xff1a;…

如何通过DAU分析活跃用户?(案例:python绘制箱体图)

前言&#xff1a;本文内容以游戏产品为基础进行讲解&#xff0c;内容为以下4部分&#xff1a; 1. 如何理解DAU反映了哪些问题&#xff1f; 2. 有哪些因素会影响DAU变动&#xff1f; 3. 如何解读DAU的“箱体图”&#xff1f; 4. 如何使用python绘制“箱体图”&#xff1f; DAU的…

【数据分析】产品日活DAU下降,怎么分析

目录 案例简介 第一步&#xff1a;确认数据真实性 第二步&#xff1a;明确定义&#xff0c;并拆解指标&#xff0c;进一步定位原异常部分 第三步&#xff1a;根据几个常见维度初步拆分数据 第四步&#xff1a;进一步做假设并细分深入&#xff0c;得出结论 案例分析 例题…

数据分析——DAU下降问题(转)

文章转自&#xff1a; DAU异常下降该如何分析 1. 梳理公司的用户增长模式 尽管不同业务形态、以及不同发展阶段的公司&#xff0c;其用户增长模式各有差异&#xff0c;但都可以从拉新策略和促活策略进行分解。 常见的拉新策略有&#xff1a; 流量采购。比如通过厂商预装、…

有赞一面:亿级用户DAU日活统计,有几种方案?

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如极兔、有赞、希音、百度、网易、滴滴的面试资格&#xff0c;遇到一几个很重要的面试题&#xff1a; (1) 亿级用户场景&#xff0c;如何高性能统计日活&#xff1f; (2) 如何实现亿…

数据分析——用户粘性指标 DAU/MAU

&#xff08; 一 &#xff09;定义 DAU&#xff0c;即&#xff1a;Daily Active User&#xff0c;指日活跃用户数&#xff1b; MAU&#xff0c;即&#xff1a;Monthly Active User&#xff0c;指月活跃用户数。 日活/月活就是体现用户粘性最频繁使用的指标。日活跃用户占月活…

数据分析体系 - 用户粘性(DAU/MAU 和 月人均活跃天数)

对于常见的App&#xff0c;用户粘性的取值范围就是3%~100%&#xff0c; 不同领域的App也会有不同的基准值&#xff0c; 例如移动游戏会以20%为基线&#xff0c; 而工具类App会以40%为基线。 用户粘性的两个计算指标&#xff1a; 1、DAU/MAU 2、月平均活跃人数 这里其实…