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

article/2025/9/18 7:21:57

目录:
java虚拟机汇总

  1. class文件结构分析
    1).class文件常量池中的常量项结构
    2). 常用的属性表的集合
  2. 类加载过程
    1).类加载器的原理以及实现<<== 现在位置
  3. 虚拟机结构分析
    1).jdk1.7和1.8版本的方法区构造变化
    2).常量池简单区分
  4. 对象结构分析
    1).压缩指针详解
  5. gc垃圾回收
  6. 对象的定位方式

目的:看懂4,并且自己实现一个类加载器,前三条为理论知识,懂了可以跳过,最主要的是自己实现一个,并完成功能
1.类加载器是什么东西
2.类加载器的种类
3.类加载器的机制
4.自己实现一个类加载器
在这里引用大佬的链接,这个是讲的很详细的,如果心急,不想细细研究那就直接看我总结的吧

类加载器是什么东西?

1.类加载器就是加载所有的类的工具,它加载的类在内存中只会存在一份,也就是生成的堆中的Class对象。不可以重复加载
2.在我们java编码里,一个类是用全限定名(包名加类名)标识的唯一的一个类,但在jvm里是根据类加载器+全限定名来标识,也就是说不同类加载器加载的同一个类,在内存中也是不同的Class

类加载器的种类

java有三种类加载器(面试会问)
1)根类加载器(bootstrap class loader)
2)扩展类加载器(extension class loader)
3)应用类加载器(application class loader)
关系如下图所示
在这里插入图片描述
简单说一下用途
启动类加载器
大白话来说,加载核心类的,底层c++实现的,jvm启动时候就去你jdk加载jre/lib/rt.jar下的class,我们也触碰不到,并且它是不继承classLoader的,
查找范围:sun.mic.boot.class下面的路径

扩展类加载器:
它负责加载JRE的扩展目录,由Java语言实现,父类加载器为null(因为关系上父类加载器是启动类加载器,但是启动类加载器是c++,所以这里拟为null)。(注意父类加载器不代表那是他的父类,只是一个关系的称呼而已,你可以用getParent方法来查看此类的父加载器)
查找范围:java.ext.dirs下面的路径

应用类加载器
这个是和我们相关的,父加载器是扩展类加载器,我们默认自己实现的类加载器都是此应用类加载器的子加载器
查找范围:java.class.path (也就是你的工程下的bin目录)下面的路径

3.类加载器的机制

双亲委派机制
即一个类加载器接收到加载此类的请求时会先去请求父类加载器加载此类,如果父类还有父类则继续传给父类的父类,当找到最根的类加载器时(启动类加载器),加载器会尝试在自己的查找范围内找此类的class文件,若找到则加载,找不到就往回走,即告诉子类我不能处理这个任务,然后子类看看在他的范围能不能找到,找到就加载,再找不到继续往下传,都找不到报错
总之一句话:有事往上级抛,上级都处理不了我再处理

缓存机制
缓存机制指,类加载器加载时将缓存所有加载过的class,存在每一个类加载器的缓冲中,下次获取此类的class时先去缓存中找,那么结合双亲委派机制,流程应该是这样的
拿到加载请求后,先去我的缓存里找,没有了往上抛,上面接收到了,直接在自己的缓存找,没有了再往上抛,如果上面没有了,那就尝试加载,找不到了,往下扔,然后下面的拿到直接尝试加载,找不到了,再往下扔,下面没有了就报错

4.自己实现一个类加载器

上面都是些理论的知识,一定要实战才能加深印象!!!上面的可以半知半解,下面的一定要会,会了再去理解上面的知识
目的:自己写一个类加载器,加载一个D盘目录下的Test.class文件并获取实例

在这里插入图片描述在这里插入图片描述

自定义类加载器步骤
写一个类继承ClassLoader
复写findClass()方法。
在findClass()方法中调用defineClass()。(方法什么意思,看注释!)

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class MyClassLoader extends ClassLoader {//自定义加载器时传进一个路径名,就跟其他类加载器的查找范围一样,//当从顶层开始查找时,任务从上面扔到我们这,我们也将去这个位置找那个类,找不到就往下抛String filePath;//构造器public MyClassLoader(String filePath) {this.filePath = filePath;}//这是继承的方法,要求传入一个文件名 例如:Test,返回一个Class对象,其中实际调用的是difineClass@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {//这个是加上个.class后缀String fileName = name+".class";FileInputStream fi = null;ByteArrayOutputStream bos =null;byte[] bytes = null;try {fi = new FileInputStream(new File(filePath,fileName));bos = new ByteArrayOutputStream();int i =0;while((i = fi.read())!=-1){bos.write(i);bos.flush();}bytes = bos.toByteArray();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {fi.close();} catch (IOException e) {e.printStackTrace();}try {bos.close();} catch (IOException e) {e.printStackTrace();}}//最核心的方法,defineClass通过字节数组帮你创建了class对象return defineClass(name,bytes, 0, bytes.length);}public static void main(String[] args) {MyClassLoader myClassLoader = new MyClassLoader("D:\\");try {Class<?> test = myClassLoader.loadClass("Test");if(test!=null){Object x = test.newInstance();Method getA = test.getDeclaredMethod("getA", null);//调用方法System.out.println(getA.invoke(x,null));}else{System.out.println("err");}} catch (ClassNotFoundException | NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}
}
结果:3

注意现在我们的我们的目录结构,没有其他类,只有我们的类加载器,下面做对比会加上Test类
在这里插入图片描述
此时注意我们覆盖的是findClass方法,调用的是确是loadClass方法,其实loadClass方法会将此Test类扔到父加载器,一直扔到最顶端,然后开始向下调用此类加载器的findClass方法查找,如果找到,就返回一个实例,找不到继续往下扔
所以说要不破坏双亲委派机制就不要覆盖loadclass方法(面试题:怎么破坏双亲委派)
接下来注意:
在这里插入图片描述
我们在idea里又创建了同名的Test文件,带大家分析一遍流程,分析执行结果:
1.首先调用我们自己写的类加载器,自己创建的类加载器,默认父类加载器是applicationClassLoder,发现缓存里没有,上面走起
2.Test加载请求向上到applicationClassLoder,然后applicationClassLoder发现他的缓存里没有,继续向上抛
3.然后到extClassLoder里面了,他发现缓存里也没有,继续向上抛,此时发现extClassLoder父类加载器是null,所以直接抛给bootstrapClassLoder
4.bootstrapClassLoder发现缓存里也没有,然后又发现此时自己就是最顶层,于是开始在自己的路径sun.mic.boot.class里找,没有,自己处理不了,向下抛
5.同理ext也发现在自己路径里找不到,往下抛,
6.注意!此时已经到了application类加载器里了,找!java.class.path 路径,也就是bin路径,发现我们有了一个Test,好了,他不会在向下抛给我们自己创建的类加载器了,也就是说我们定义的类加载器的findClass没有被执行,直接让applicationClassloader加载了,于是报错
在这里插入图片描述
这就是双亲委派机制的流程,这样做有什么好处
1.保护我们原有类:如果没有这个机制,如果你在appicationClassLoader管理的目录下(bin目录)创建了一个Object类,好了,你用到的所有Object类全部都加载你自己创建的Object类,这样你就可以随意篡改原来的Object类(也可以是其他类),不安全
2.这样做可以使加载有优先级,避免类的重复加载,父亲已经加载了该类时,就没有必要子ClassLoader再加载一次


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

相关文章

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、月平均活跃人数 这里其实…

数据分析——DAU下降/上升原因分析

本文是对“DAU变动原因”问题进行的思考整理&#xff0c;仅作记录&#xff0c;欢迎讨论。 &#xff08; 一 &#xff09;思维框架 图版&#xff1a; 文版&#xff1a; 内部原因&#xff1a; 1. 数据验证 如果DAU上升或者下降&#xff0c;且非日常波动&#xff0c;需先确…

数据分析 — 用户粘性的两个计算指标(DAU/MAU和月人均活跃天数)

很多运营都了解DAU&#xff08;日活跃用户数&#xff09;和MAU&#xff08;月活跃用户数&#xff09;的重要性&#xff0c;但在某些情况下这两个数值本身并不能反映出太多问题&#xff0c;这个时候就要引用到【DAU/MAU】的概念&#xff0c;即【日活/月活】。 用户粘性的两个计…

峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?

小游戏《羊了个羊》 短短的7天内&#xff0c;DAU突破了1亿、吞吐量峰值21WQps。 《羊了个羊》运营后台数据显示&#xff0c;在短短的7天内&#xff0c;这款小游戏的DAU就突破了1亿。 要知道&#xff0c;除了王者荣耀、原神等屈指可数的现象级手游之外&#xff0c;1亿DAU是这个…

dau、mau、pcu、dnu、wau、acu、uv分别是什么意思?

dau、mau、pcu、dnu、wau、acu、uv的意思是什么?怎么分析? DAU(Daily Active User)日活跃用户数量。常用于反映网站、互联网应用或网络游戏的运营情况。 MAU(monthly active users)月活跃用户人数。是在线游戏的一个用户数量统计名词&#xff0c;数量越大意味着玩这款游戏的人…

数据化运营04 DAU、MAU、UV:谁是最有参考价值的活跃指标?

活跃类指标是重要的用户质量指标&#xff0c;代表了产品上真正的用户&#xff0c;代表了具备营销价值的用户群&#xff0c;是几乎所有产品运营的重点。 在这一讲中&#xff0c;我会主要向你介绍 UV、DAU、MAU&#xff0c;以及每日使用时长和每日打开频次等指标。 你是否思考过…