使用类加载器java.net.URLClassLoader时的奇怪问题?

先写个继承java.net.URLClassLoader的类,如下:
[code="java"]
package kite.jvm;

import java.net.URL;
import java.net.URLClassLoader;

public class OneURLClassLoader extends URLClassLoader {
// 类加载器的parent默认为系统AppClassLoader.
public OneURLClassLoader(URL[] urls) {
super(urls);
}
// 使用父类的findClass(String name)方法加载类.
public Class findClass(String name) throws ClassNotFoundException {
return super.findClass(name);
}
}
[/code]
接下来写个接口,如下:
[code="java"]
package kite.jvm;

public interface OneInterface {}

[/code]
紧接着写个实现上面接口的一个类,如下:
[code="java"]
package kite.jvm;

public class Constant implements OneInterface {}

[/code]
好了,写个含main方法的类测试下,如下:
[code="java"]
package kite.jvm;

import java.net.URL;

public class Run {
public static void main(String[] args) throws Exception {
// class字节码所在的位置.
String dir = "file:/Development/workspace/jvm/bin/";
URL url = new URL(dir);
OneURLClassLoader oucl = new OneURLClassLoader(new URL[]{url});
// 用类加载器加载kite.jvm.Constant并返回它的class对象.
Class c = oucl.findClass("kite.jvm.Constant");
// 根据class对象c实例化一个对象,用它的接口类型(OneInterface)做类型转换.
OneInterface instance1 = (OneInterface) c.newInstance();
// 根据class对象c实例化一个对象,用它的实际类型(Constant)做类型转换.
//Constant instance2 = (Constant) c.newInstance();
System.out.println(instance1);
//System.out.println(instance2);
}
}

[/code]
如上代码运行结果打印如下:
[code="java"]
kite.jvm.Constant@b6e39f
[/code]
如果打开注释掉的那两条代码,运行结果打印如下:
[code="java"]
Exception in thread "main" java.lang.ClassCastException: kite.jvm.Constant cannot be cast to kite.jvm.Constant
at kite.jvm.Run.main(Run.java:12)
[/code]
问题:解释下异常的出现,在此情景中接口和实际类型转化的区别?先谢谢大家了。
注:附件里是源代码。

http://www.iteye.com/topic/98178 这个不错 那篇很系统 javaEye就是有很多java牛人。

到时给你看看 !

[code="java"]Class c = oucl.findClass("kite.jvm.Constant"); [/code]
改为
[code="java"]Class c = oucl.loadClass("kite.jvm.Constant"); [/code]
就可以了

你的问题我重现了,但是我跟你一样迷惑,所以弄了一会儿。饭都玩了吃。
增加一个类
[code="java"]
public class MyConstant extends Constant{

}
[/code]

改写Run:
[code="java"]
public class Run {
public static void main(String[] args) throws Exception {
Integer a = new Integer(1);
Object b = (Object)a;
String dir = "file:/test/learn/bin/";
URL url = new URL(dir);
OneURLClassLoader oucl = new OneURLClassLoader(new URL[]{url});
// Class c = oucl.findClass("kite.jvm.MyConstant");
Class c = Class.forName("kite.jvm.MyConstant");

    OneInterface instance1 = (OneInterface) c.newInstance();
    Constant instance2 =  (Constant)c.newInstance();

    System.out.print(c.newInstance().getClass().getName());
    Object instance3 = (Object)c.newInstance();
    MyConstant instance4 = (MyConstant)c.newInstance();

    System.out.println(instance1);
    System.out.println(instance2);
    System.out.println(instance3);
    System.out.println(instance4);
}

}
[/code]

MyConstant 的命名空间为本地,
通过下面的代码后
[code="java"]
// Class c = oucl.findClass("kite.jvm.MyConstant");
[/code]
这个就是导致出错的真正原因。实际上是一个类加载器不一致 的原因。你先去了解一下类加载器。我去吃点饭有时间 再给你弄。

在java中类加载器不一样 强制转换会报错。改为loadClass使用的类加载器 就与Class.forName使用的一样。

其实你这个问题在javaeye我回答很多次了.

OneInterface instance1 = (OneInterface) c.newInstance(); (1)
// 根据class对象c实例化一个对象,用它的实际类型(Constant)做类型转换.

//Constant instance2 = (Constant) c.newInstance();(2)

System.out.println(instance1);

//System.out.println(instance2);

上一个GGMM回答的在java中类加载器不一样,强制转换会报错你能理解这个就好说了.

首先为什么(1)可以,因为OneURLClassLoader在加载Constant的时候发现需要加载
OneInterface(因为他是其接口),因为OneURLClassLoader找不到OneInterface,所以最终委其父也就是appclassloader加载了OneInterface.
而转换后的OneInterface instance1也是appclassloader加载的(其实是同一个,一个类在同一laoder里,不会加载两次),自然不存在问题.

而(2)不可以,因为外部的Constant instance2 是appclassloader加载的,而内部的即C是OneURLClassLoader加载的,当然不能转换.

这里为什么说OneURLClassLoader的父是appclassloader,我想你一定知道,我就不班门弄斧了.