java 自定义类加载器
百度了一下,通篇全部都是启动类加载器,扩展类加载器,应用程序类加载器,还有就是双亲委托模式 。
可是一圈下来,新手们依然不知道如何自定义一个类加载器,来生动的展现什么是类加载器。
首先我们在E:upload下新建一个a/BB.java文件。
代码如下:
package a; public class BB { private String a; public BB(){ } public BB(String a){ this.a=a; } public static void main(String[] args) { System.out.println("aaaaaaaaaa"); } }
编译后出现BB.class字节码文件
退回到上级目录,因为包是到a目录的。执行java a.BB;正确执行main方法
现在我们回到IDea编辑器中,将BB.class文件读取到内存,并且利用反射进行实例化。
自定义类加载器 MyClassLoader.java
package a; import java.io.*; import java.lang.reflect.Field; public class MyClassLoader extends ClassLoader{ @Override protected Class<?> findClass(String name) { byte[] bytes=null; //将点替换成斜杠 String fileName=name.replaceAll("\\.","/"); StringBuilder sb=new StringBuilder("E:"); sb.append(File.separator); sb.append("upload"); sb.append(File.separator); sb.append(fileName); sb.append(".class"); fileName=sb.toString(); try { InputStream is=new FileInputStream(fileName); ByteArrayOutputStream bos=new ByteArrayOutputStream(); byte[] buf=new byte[1024]; int r=0; while ((r=is.read(buf))!=-1){ bos.write(buf,0,r); } bytes=bos.toByteArray(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return defineClass(name,bytes,0,bytes.length); } public static void main(String[] args) throws Exception{ //自定义类加载器对象1 MyClassLoader c1=new MyClassLoader(); String className="a.BB";
//loadClass调用的就是findClass() Class clazz1=c1.loadClass(className); //自定义类加载器对象2 MyClassLoader c2=new MyClassLoader(); Class clazz2=c2.loadClass(className); System.out.println(clazz1.getClassLoader()); System.out.println(clazz2.getClassLoader()); if(clazz1!=clazz2){ System.out.println("不同的类加载器对象加载相同的class文件,会产生不同的类对象"); } Object obj1=clazz1.getDeclaredConstructor(new Class[]{String.class}).newInstance("自定义加载器加载进内存的"); Field fa=clazz1.getDeclaredField("a"); fa.setAccessible(true);//将私有变量设置成可以访问的权限 System.out.println(fa.get(obj1)); } }
执行结果:
e.MyClassLoader@2b193f2d
e.MyClassLoader@4dc63996
不同的类加载器加载相同的class文件,会产生不同的类对象
自定义加载器加载进内存的
很明显clazz1和clazz2是两个类。
给BB.java中构造器传入的字符串:“自定义加载器加载进内存的” 也在上面打印出来了。
注意:如果将a/BB.java文件拷贝到idea编辑器中。那么MyClassLoader中的findClass就不会执行了。
因为MyClassLoader c1和MyClassLoader c2都继承自ClassLoader,所以直接交给上级类加载器加载应用程序类加载器:Application ClassLoader;
应用程序类加载器会首先找到a/BB.class文件,并加入内存;此时就不会在继续x向下传播调用加载了。
类加载器在加载的时候虚拟机会首先调用加载器的私用方法loadClassInternal()
而这个方法唯一作用就是调用自己的loadClass()方法,如果loadClass()加载失败了,则会调用自己的findClass()。
loadClass()也能被重写,但是我们不会这样做,因为这样做的话,所有的类都会走这个方法来加载类;那么虚拟机内置的一些类也会用这个方法里面的逻辑来加载,固定会报错。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2015-05-20 Java线程详解