工作目录
自定义类加载器
package X.service;
import java.io.*;
public class MyClassLoader extends ClassLoader{
public MyClassLoader(ClassLoader parent){
super(parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//1.获取class文件二进制字节数组
byte[] data = null;
try{
System.err.println("寻找名字为"+name + "的类"+"-------------------");
// 将.转为双杠
String namePath = name.replaceAll("\\.", "\\\\");
String classFile = "D:\\HuaDong\\party\\test\\src\\"+ namePath + ".class";
System.err.println("路径:"+classFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(classFile);
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes)) != -1){
baos.write(bytes,0,len);
}
data = baos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 2.字节码加载到 JVM 的方法区,
// 并在 JVM 的堆区建立一个java.lang.Class对象的实例
// 用来封装 Java 类相关的数据和方法
return super.defineClass(name,data,0,data.length);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.err.println("使用自定义加载器-------------------");
Class clazz = null;
clazz = this.findClass(name);
if(clazz != null){
return clazz;
}
// 自己加载不了,再调用父类loadClass,保持双亲委托模式
return super.loadClass(name, false);
}
}
想加载的类
自定义加载器是加载相应的.class文件,使用javac编译.java文件得到.class文件
package X.entity;
public class Idiot {
private String name;
private String action;
public Idiot(String name, String action) {
this.name = name;
this.action = action;
}
}
WeiningPayServiceTest使用自定义类加载器
@Test
void testMyClassLoader() throws ClassNotFoundException {
MyClassLoader myClassLoader = new MyClassLoader(MyClassLoader.class.getClassLoader());
System.err.println("MyClassLoader的父类加载器:"+myClassLoader.getParent());
Class clazz = myClassLoader.loadClass("net.whir.hos.partyfund.entity.Idiot");
System.err.println("类加载器:"+clazz.getClassLoader());
}
测试结果
可知其父类加载器是应用类加载器。
为什么要找Object.class,并且还找不到Object.class ?
因为java中所有类都继承了Object,而加载自定义类X.entity.Idiot;,之后还会加载其父类,而最顶级的父类Object是java官方的类,只能由BootstrapClassLoader加载。
修正
在上述结果上得知,目前要处理object.class加载不出来的问题,考虑将自定义类的加载器的父类设置为启动类加载器
1)修改自定义类加载器
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//1.获取class文件二进制字节数组
byte[] data = null;
try{
System.err.println("寻找名字为"+name + "的类"+"-------------------");
if(name.startsWith("java.")){
return null;
}
2)修改父类
@Test
void testMyClassLoader() throws ClassNotFoundException {
MyClassLoader myClassLoader = new MyClassLoader(null);
System.err.println("MyClassLoader的父类加载器:"+myClassLoader.getParent());
Class clazz = myClassLoader.loadClass("X.entity.Idiot");
System.err.println("类加载器:"+clazz.getClassLoader());
}
结果
成功了,Idiot类由自定义的类加载器MyClassLoader加载的,并且其父级类加载器是启动类加载器,双亲委派模型被破坏了。
备注:
借鉴了这位作者的文章 https://www.cnblogs.com/shoshana-kong/p/17005974.html