gpt4 book ai didi

java - 当我使用自定义类加载器时出现 ClassCastException

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:12:41 25 4
gpt4 key购买 nike

我尝试了解 java 类加载。我写了例子:

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);
}
}
}

我还有接口(interface):

public interface ISexyInterface {

public void makeBar ();

}

和类:

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();
}

此示例运行良好并产生以下输出:

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

但是让我们一起玩:

    //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 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)

请解释这种行为。

附言

我知道如果同一个类加载了 2 个不同的加载器。它算作 2 个不同的类。

最佳答案

If uncomment this line I see following output:......

Class sexy_cla = xloa.loadClass("sur.che.SexyClassForLoader");

sur.che.SexyClassForLoaderXloader 加载,因为它有一个接口(interface) sur.che.ISexyInterface 然后是 jvm 将使用 sur.che.SexyClassForLoaderclassloader 加载此接口(interface)。
但是对于这个声明:

System.out.println(ISexyInterface.class.getClassLoader());

因为包含main方法AppLoader加载,所以jvm会使用AppLoader加载< em>ISexyInterface.class.

 ISexyInterface local_sexy = (ISexyInterface) sexy_ob;

很明显,这个ISexyInterface的类加载器是AppLoader,但是SexyClassForLoader的内部依赖(ISexyInterface)是由加载的xLoader。换句话说,jvm 中有两个 ISexyInterface.class,一个由Xloader 加载,另一个由App sexy_ob 实现了由 Xloader 加载的 ISexyInterface.class。您尝试将 sexy_ob 转换为 ISexyInterface 类型(由 App 加载)。所以 castException

如果注释,只有一个 ISexyInterface .classApp 加载。所以一切正常。

关于java - 当我使用自定义类加载器时出现 ClassCastException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41610912/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com