美文网首页
自定义类加载器

自定义类加载器

作者: jsjack_wang | 来源:发表于2018-01-31 16:19 被阅读0次

    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<ClassLoaderTest> testClassOne =
                        (Class<ClassLoaderTest>) classLoader.findClassByFilePathAndName(filePath, name);
                ClassLoaderTest test = testClassOne.newInstance();
                test.say();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            try {
                Class<ClassLoaderTest> testClassOne =
                        (Class<ClassLoaderTest>) 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

    相关文章

      网友评论

          本文标题:自定义类加载器

          本文链接:https://www.haomeiwen.com/subject/wvhlzxtx.html