https://blog.csdn.net/weixin_36586120/article/details/117457014

双亲委派模型并不是一个具有强制性约束的模型,而是Java设计者推荐给开发者们的类加载器实现方式。这个委派和加载顺序完全是可以被破坏的。

如果想自定义类加载器,就需要继承ClassLoader,并重写findClass,如果想不遵循双亲委派的类加载顺序,还需要重写loadClass

1、直接自定义类加载器加载

如下是一个自定义的类加载器TestClassLoader,并重写了findClassloadClass

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,也会加载父类ObjectObjectstudy.stefan.classLoader.Demo并不在同个目录,那就找到Object.class的目录(将jre/lib/rt.jar解压),修改TestClassLoader#findClass如下:

遇到前缀为java.的就去找官方的class文件。

运行测试代码:

还是报错了!!!