https://blog.csdn.net/weixin_36586120/article/details/117457014
双亲委派模型并不是一个具有强制性约束的模型,而是Java设计者推荐给开发者们的类加载器实现方式。这个委派和加载顺序完全是可以被破坏的。
如果想自定义类加载器,就需要继承ClassLoader
,并重写findClass
,如果想不遵循双亲委派的类加载顺序,还需要重写loadClass
。
如下是一个自定义的类加载器TestClassLoader
,并重写了findClass
和loadClass
:
public class TestClassLoader extends ClassLoader {
public TestClassLoader(ClassLoader parent) {
super(parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 1、获取class文件二进制字节数组
byte[] data = null;
try {
System.out.println(name);
String namePath = name.replaceAll("\\\\\\\\.", "\\\\\\\\\\\\\\\\");
String classFile = "C:\\\\\\\\study\\\\\\\\myStudy\\\\\\\\ZooKeeperLearning\\\\\\\\zkops\\\\\\\\target\\\\\\\\classes\\\\\\\\" + namePath + ".class";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(new File(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 this.defineClass(name, data, 0, data.length);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException{
Class<?> clazz = null;
// 直接自己加载
clazz = this.findClass(name);
if (clazz != null) {
return clazz;
}
// 自己加载不了,再调用父类loadClass,保持双亲委托模式
return super.loadClass(name);
}
}
测试:
初始化自定义的类加载器,需要传入一个parent
,指定其父类加载器,那就先指定为加载TestClassLoader
的类加载器为TestClassLoader
的父类加载器吧:
public static void main(String[] args) throws Exception {
// 初始化TestClassLoader,被将加载TestClassLoader类的类加载器设置为TestClassLoader的parent
TestClassLoader testClassLoader = new TestClassLoader(TestClassLoader.class.getClassLoader());
System.out.println("TestClassLoader的父类加载器:" + testClassLoader.getParent());
// 加载 Demo
Class clazz = testClassLoader.loadClass("study.stefan.classLoader.Demo");
System.out.println("Demo的类加载器:" + clazz.getClassLoader());
}
运行如下测试代码,发现报错了:
找不到java\\\\lang\\\\Object.class
,我加载study.stefan.classLoader.Demo
类和Object
有什么关系呢?
转瞬想到java中所有的类都隐含继承了超类Object
,加载study.stefan.classLoader.Demo
,也会加载父类Object
。Object
和study.stefan.classLoader.Demo
并不在同个目录,那就找到Object.class
的目录(将jre/lib/rt.jar
解压),修改TestClassLoader#findClass
如下:
遇到前缀为java.
的就去找官方的class文件。
运行测试代码:
还是报错了!!!