关于自定义ClassLoader的使用问题

marshalbin 发布于 2017/02/15 10:48
阅读 452
收藏 1

我自己定义了一个ClassLoader叫MyClassLoader,它继承了ClassLoader,重写了findClass方法(源码在下面)。MyClassLoader中指定的读取路径是当前classpath(即app的bin目录)。我用MyClassLoader加载自定义的Test2类(该类文件也在app的bin目录下),从获得的实例对象中输出它的classloader,输出的是MyClassLoader,但是依照双亲委托模型,加载该类的不应该是AppClassLoader吗(因为AppClassLoader的职责是从App的classpath下加载类)?怎么会是我自己定义的MyClassLoader呢?请大家帮我解答一下,谢谢。源码如下:

Test.java源码:

public class Test{
    static class MyClassLoader extends ClassLoader{
        public MyClassLoader(){
            super();
        }
        
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {  
            String classPath = MyClassLoader.class.getResource("/").getPath(); //得到classpath  
            String fileName = name.replace(".", "/") + ".class" ;  
            File classFile = new File(classPath , fileName);
            if(!classFile.exists()){  
                throw new ClassNotFoundException(classFile.getPath() + " 不存在") ;  
            }  
            ByteArrayOutputStream bos = new ByteArrayOutputStream() ;  
            ByteBuffer bf = ByteBuffer.allocate(1024) ;  
            FileInputStream fis = null ;  
            FileChannel fc = null ;  
            try {  
                fis = new FileInputStream(classFile) ;  
                fc = fis.getChannel() ;  
                while(fc.read(bf) > 0){  
                    bf.flip() ;  
                    bos.write(bf.array(),0 , bf.limit()) ;  
                    bf.clear() ;  
                }  
            } catch (FileNotFoundException e) {  
                e.printStackTrace();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }finally{  
                try {  
                    fis.close() ;  
                    fc.close() ;  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
            return defineClass(bos.toByteArray() , 0 , bos.toByteArray().length) ;  
        }  
    }
    
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        MyClassLoader mycl = new MyClassLoader();
        Class<?> c = mycl.findClass("Test2");
        Object o = c.newInstance();
        System.out.println(o.getClass().getClassLoader());
    }

}

Test.java源码:

public class Test2 {

    public Test2(){
        
    }
}

加载中
1
m
marshalbin

经过这几天的学习,我好想找到了答案,请大家评判一下:

在classpath目录下的class类文件,AppClassLoader会自动去加载,但是我自己定义的MyClassLoader也可以去加载,这两个过程互不影响。只不过AppClassLoader和MyClassLoader加载后,这个类就在不同命名空间下同时创建了对象,在main方法中执行System.out.println(o instanceof Test2);结果为false,o是由MyClassLoader加载生成的,而Test2是由AppClassLoader加载的,所以结果是false。

0
cyb_beta
cyb_beta

mycl.findClass("Test2"); 这里应该调用loadClass方法,

loadClass方法才会依照双亲委托模型定义clas

0
m
marshalbin

请问:findClass和loadClass谁符合双亲委派模型?

0
m
marshalbin

谢谢大家,我通过看源码明白了。

如果通过自定义的MyClassLoader调用loadClass方法加载类,则按照双亲委托模型机制进行类加载;如果调用findClass方法加载类,则直接通过自定义的类进行类加载。

-1
上郡刀客
上郡刀客

哪个ClassLoader实例调用的defineClass,就是哪个加载的撒……

OSCHINA
登录后可查看更多优质内容
返回顶部
顶部