自定义类加载器

1.基本概念(之前介绍过,写点之前可能没有说过的)

JVM认为同一个类的2个条件,第一相同的类加载器引用,第二相同的名称(包名+类名)。也就是说,同一个.class文件被不同的类加载器加载,却不是相同的类。

注意:类加载器三个机制(委托 单一 可见)

2.自定义类加载器

2.1 如果不想打破双亲委派模型, 那么只需要重写findClass方法即可
2.2 如果想打破双亲委派模型,那么就重写整个loadClass方法

3.关于1中提出相同类的概念的Demo

3.1 ClassLoaderTest作为测试类
public class ClassLoaderTest {
    public void say() {
        System.out.println("This is Test.");
    }
}
3.2 类加载器
public class CustomAClassLoader extends ClassLoader {
    private String filePath = null;

    protected synchronized Class findClassByFilePathAndName(String filePath, String name)
            throws ClassNotFoundException {
        if (Objects.isNull(filePath) || Objects.isNull(name)) {
            throw new IllegalArgumentException("参数不能为空");
        }
        this.filePath = filePath;
        return findClass(name);
    }

    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(filePath)
                .append(name.replace(".", "/"))
                .append(".class");
        FileInputStream fis = null;
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            fis = new FileInputStream(new File(stringBuilder.toString()));
            byte[] bytes = new byte[1024];
            int len = -1;
            while ((len = fis.read(bytes)) != -1) {
                baos.write(bytes, 0, len);
            }
            return this.defineClass(name, baos.toByteArray(), 0, baos.size());
        } catch (Exception e) {
            throw new ClassNotFoundException();
        } finally {
            closeStream(fis);
            closeStream(baos);
        }
    }

    private void closeStream(InputStream stream) {
        if (Objects.nonNull(stream)) {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void closeStream(OutputStream stream) {
        if (Objects.nonNull(stream)) {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
3.3 测试
public class ClassLoaderDemo {
    public static void main(String[] args) {
        CustomAClassLoader classLoader = new CustomAClassLoader();
        String name = "com.boomsecret.classloader.ClassLoaderTest";
        try {
            String filePath = "C:/MineProjects/JavaDemo/target/classes/";
            Class testClassOne =
                    (Class) classLoader.findClassByFilePathAndName(filePath, name);
            ClassLoaderTest test = testClassOne.newInstance();
            test.say();
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            Class testClassOne =
                    (Class) ClassLoaderDemo.class.getClassLoader().loadClass(name);
            ClassLoaderTest test = testClassOne.newInstance();
            test.say();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
result:
    ClassCastException
总结:出现ClassCastException原因,AppClassLoader已经加载ClassLoaderTest,而CustomAClassLoader再加载,他们的类加载器是不同的,所以不是相同的Class,也就出现了ClassCastException

源码地址:https://gitee.com/jsjack_wang/JavaDemo

你可能感兴趣的:(自定义类加载器)