3.代码实现自定义类加载器
手把手叫你写类加载器。
了解了类加载器的双亲委派机制, 也知道了双亲委派机制的原理,接下来就是检验我们学习是否扎实了,来自定义一个类加载器
一. 回顾类加载器的原理
还是这张图,类加载器的入口是c++调用java代码创建了JVM启动器,其中的一个启动器是sun.misc.Launcher启动器。这个启动器启动并加载的AppClassLoader和ExtClassLoader。然后调用launcher.getClassLoader()方法获取loader对象, loader对象本质是一个ClassLoader,然后调用了ClassLoader的loadClass("...")方法加载类。也是在loadClass("...")方法里实现了双亲委派机制。
详细原理参考文章:https://www.cnblogs.com/ITPower/p/15363400.html
二、自定义类加载器分析
对于类加载器, 我们知道他的重点是loadClass(...)方法, 里面的双亲委派机制也是在loadClass方法里面实现的. loadClass方法里面实际上去加载类的是findClass()方法. 对于我们自定义的类加载器来说需要做到两点即可
-
这个自定义的类加载器继承自ClassLoader
-
这个类加载器要重写ClassLoader类中的findClass()方法
另外我们还可以参考AppClassLoader和ExtClassLoader来写。
三、自定义类加载器实现
下面我自己定义了一个类加载器
第一步:自定义类加载器继承自ClassLoader抽象类,然后定义一个构造方法, 用来接收要加载的类名
第二步:重写核心方法findClass(String name)
这里有两步操作,
第一个是: 从类路径中读取要加载类的文件内容, 自定义
第二个是: 调用构造类的方法, 调用的系统的defineClass
接下来看看自定义的loadByte是如何实现的
这里的实现就是找到类, 并且将类的内容读取出来, 转换成二进制的字节码, 返回
最后一部分就是如何调用了.
用类加载器加载类, 然后实例化, 使用反射机制调用User1 的方法sout
public class User1 { public void sout() { System.out.println("进入到User1"); } }
这里面System.out.println(clazz.getClassLoader().getClass().getName()); 获取当前类的类加载器, 猜一猜这里打印的会是谁?
看到了么? 是AppClassLoader, 为什么呢?
原因是我的项目里已经有一个类User1了
我们自定义类加载器的父类是AppClassLoader. 而程序代码中的User1刚好是被AppClassLoader加载, 因为找到了,所以就不会再去我们指定的文件夹中查找了
这就是类的双亲委派机制的特点.
那么如果我们将项目中的User1类删除掉, 这是类加载器是谁呢? 当然就是我们自定义的类加载器了.
那么问题来了, 自定义类加载器的父类为什么是AppClassLoader呢?
四. 分析自定义类加载的父类为什么是appClassLoader?
我们来看一下源码
我们自定义的类加载器, 继承自ClassLoader类加载器, 那么在调用自定义类加载器的构造方法之前, 应该先加载父类ClassLoader的无参构造函数.
首先会执行ClassLoader的无参的构造方法.
而无参的构造方法会调用自身的构造方法
里面有一个parent, 我们就是要看看这个parent到底是谁呢. 来看看getSystemClassLoader()方法
之前我们已经研究过getClassLoader()这个方法了, 这里面定义的loadClass是谁呢?就是AppClassLoader.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类