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。

你可能感兴趣的:(F#)