Java 使用自定义类加载器时的ClassCastException
我试图理解java分类。我写了一个例子:Java 使用自定义类加载器时的ClassCastException,java,jvm,classloader,classcastexception,dynamic-class-loaders,Java,Jvm,Classloader,Classcastexception,Dynamic Class Loaders,我试图理解java分类。我写了一个例子: class XLoader extends ClassLoader { // карта отображения имен классов на файлы .class, где хранятся их определения HashMap<String, String> mappings; XLoader(HashMap mappings) { this.mappings = mappings
class XLoader extends ClassLoader {
// карта отображения имен классов на файлы .class, где хранятся их определения
HashMap<String, String> mappings;
XLoader(HashMap mappings) {
this.mappings = mappings;
}
public synchronized Class loadClass(String name) throws ClassNotFoundException {
try {
// важно!
// приоритет отдан именно загрузке с помощью встроенного загрузчика
if (!mappings.containsKey(name)) {
System.out.println("loadClass (" + name + ") with parent classloader");
return super.findSystemClass(name);
}
System.out.println("loadClass (" + name + ") with XLoader");
String fileName = mappings.get(name);
FileInputStream fin = new FileInputStream(fileName);
byte[] bbuf = new byte[(int) (new File(fileName).length())];
fin.read(bbuf);
fin.close();
return defineClass(name, bbuf, 0, bbuf.length);
} catch (IOException e) {
e.printStackTrace();
throw new ClassNotFoundException(e.getMessage(), e);
}
}
}
和类别:
public class SexyClassForLoader implements ISexyInterface {
...
}
主要方法:
public static void main(String[] args) throws Exception {
HashMap<String, String> mappings = new HashMap();
mappings.put("sur.che.SexyClassForLoader", "D:\\java_things\\custom-classloader\\out\\production\\custom-classloader1\\sur\\che\\SexyClassForLoader.class");
// if comment this line you will see
//mappings.put("sur.che.ISexyInterface", "D:\\java_things\\custom-classloader\\out\\production\\custom-classloader1\\sur\\che\\ISexyInterface.class");
XLoader xloa = new XLoader(mappings);
Class sexy_cla = xloa.loadClass("sur.che.SexyClassForLoader");
System.out.println("class was loaded with " + sexy_cla.getClassLoader());
Object sexy_ob = sexy_cla.newInstance();
System.out.println(sexy_ob.getClass().getClassLoader());
System.out.println(ISexyInterface.class.getClassLoader());
Thread.sleep(100);
ISexyInterface local_sexy = (ISexyInterface) sexy_ob;
local_sexy.makeBar();
}
但让我们一起玩:
//mappings.put("sur.che.ISexyInterface", "D:\\java_things\\custom-classloader\\out\\production\\custom-classloader1\\sur\\che\\ISexyInterface.class");
如果取消对此行的注释,我将看到以下输出:
loadClass (sur.che.SexyClassForLoader) with XLoader
loadClass (sur.che.ISexyInterface) with parent classloader
loadClass (java.lang.Object) with parent classloader
class was loaded with sur.che.XLoader@7f31245a
loadClass (java.lang.System) with parent classloader
loadClass (java.io.PrintStream) with parent classloader
SexyClassForLoader$$static
SexyClassForLoader$$init
sur.che.XLoader@7f31245a
sun.misc.Launcher$AppClassLoader@232204a1
make bar
loadClass (sur.che.SexyClassForLoader) with XLoader
loadClass (sur.che.ISexyInterface) with XLoader
loadClass (java.lang.Object) with parent classloader
class was loaded with sur.che.XLoader@7f31245a
loadClass (java.lang.System) with parent classloader
loadClass (java.io.PrintStream) with parent classloader
SexyClassForLoader$$static
SexyClassForLoader$$init
sur.che.XLoader@7f31245a
sun.misc.Launcher$AppClassLoader@232204a1
Exception in thread "main" java.lang.ClassCastException: sur.che.SexyClassForLoader cannot be cast to sur.che.ISexyInterface
at sur.che.Loader.main(Loader.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
请解释一下这种行为
附笔。
我理解如果同一个类加载了两个不同的加载程序。它算作两个不同的类别
如果取消对此行的注释,我将看到以下输出:。。。。。。
Xloader加载了sur.che.SexyClassForLoader,因为它有一个接口sur.che.ISexyInterface,所以jvm将使用sur.che.SexyClassForLoader的类加载器加载这个接口。
但对于这一说法:
System.out.println(ISexyInterface.class.getClassLoader());
因为包含main方法的类是由AppLoader加载的,所以jvm将使用AppLoader加载ISexyInterface.class
显然,这个ISexyInterface的类加载器是AppLoader,但是SexCyclassForLoader的内部依赖(ISexyInterface)是由xLoader加载的。换句话说,jvm中有两个ISexyInterface.class,一个由Xloader加载,另一个由App加载。sexy_ob实现了由Xloader加载的ISexyInterface.class。您尝试将SexyOb转换为ISexyInterface类型(由应用程序加载)。
所以这是个例外。如果已注释,则只有一个ISexyInterface.class由应用程序加载。所以一切都很好
Class sexy_cla = xloa.loadClass("sur.che.SexyClassForLoader");
System.out.println(ISexyInterface.class.getClassLoader());
ISexyInterface local_sexy = (ISexyInterface) sexy_ob;