ClassLoader对类的级联加载
转载请注明来自:http://chillwarmoon.iteye.com
在一个ClassLoader实例中,如果加载某个Class,那么被加载的Class是属于该ClassLoader所定义的namespace之内的。表现为不同的classloader实例虽然加载的Class完全相同,但是不能够相互类型转化,而且不能够通过类型转换成其他classloader加载的类。
但是在自定义的CustomClassLoader中,(1)Test test=(Test)clazz.newInstance()的类型转换是成功的,而且转换的是SystemClassLoader所加载的Test.class;(2)TestSub test2=(TestSub)clazz.newInstance()的类型转换是失败的。
这是为什么呢?
public class CustomClassLoader extends ClassLoader{public Class load(String arg){return getClass(arg);}public Class getClass(String arg){String path=System.getProperty("user.dir");String fullPath=path+"/bin/"+arg.replace(".", File.separator)+".class";byte[] classCode=null;File f=new File(fullPath);if(f.exists()){try {FileInputStream fis=new FileInputStream(f);classCode=new byte[fis.available()];fis.read(classCode);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return defineClass(arg,classCode, 0, classCode.length);}try {return findSystemClass(arg);} catch (ClassNotFoundException e) {e.printStackTrace();}return null;}public static void main(String args[]){Class clazz=new CustomClassLoader().load("com.hzb.classloader.TestSub");try {Test test=(Test)clazz.newInstance();TestSub test2=(TestSub)clazz.newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}答案就在于CustomClassLoader并未覆盖父类的loadClass方法,在该例子中,虽然是通过CustomClassLoader.load方法,来调用defineClass方法加载class,但是该defineClass方法仍然需要调用ClassLoader.loadClass方法来级联加载与之相关的类,包含其父类,接口。因此该例子中仅仅是对字节码文件TestSub.class进行了load,而Test仍然是由SystemClassLoader所加载,因此会出现Test test=(Test)clazz.newInstance()成功执行,而TestSub test2=(TestSub)clazz.newInstance()执行失败的情况。
如果将CustomClassLoader.load方法名称改变为loadClass,则在调用defineClass时会加载Test.class到该classLoader实例,此时再次调用Test test=(Test)clazz.newInstance()会产生类型转换失败的错误。
PS:在调用clazz.newInstance方法时,会使用classLoader的loadClass方法,来加载类的关联类。因此不同的classLoader都有着自己的namespace。