Java 为从中加载该类的对象创建引用时?
在使用Java进行一些示例编码时,我遇到了ClassCastException,从这里我将对象转换为StaticClass。谁能解释一下这里发生了什么事Java 为从中加载该类的对象创建引用时?,java,classloader,Java,Classloader,在使用Java进行一些示例编码时,我遇到了ClassCastException,从这里我将对象转换为StaticClass。谁能解释一下这里发生了什么事 public void test5() throws Exception { System.out.println(StaticClass.obj); Object newInstance = ClassLoader.getSystemClassLoader().loadClass("com.StaticClass").newIn
public void test5() throws Exception {
System.out.println(StaticClass.obj);
Object newInstance = ClassLoader.getSystemClassLoader().loadClass("com.StaticClass").newInstance();
System.out.println(newInstance.getClass().getDeclaredField("obj").get(newInstance));
Object newInstance2 = new ILoader().loadClass("com//StaticClass.class").newInstance();
System.out.println(newInstance2.getClass().getDeclaredField("obj").get(newInstance2));
StaticClass s = (StaticClass)newInstance2;
System.out.println(s.obj);
System.out.println(newInstance.getClass().getClassLoader());
System.out.println(newInstance2.getClass().getClassLoader());
}
当两个类装入器装入一个类时,实际上您有该类的两个副本。在您的场景中,当您执行类似操作时
StaticClass s = (StaticClass)newInstance2;
然后,默认情况下,您的默认系统类加载器将出现在图片中进行铸造。由于newInstance2是从另一个类加载器加载的,因此它将给出ClassCastException。这将不起作用-它们由JVM中的两个不同类对象表示,转换将失败
有关更多详细信息,请参阅以下文章和论坛条目:
类由其完全限定名和加载它的类加载器定义 这是必要的,因为只有当两个类具有相同的完全限定名且位于相同的位置(相同的类装入器)时,它们才是相同的 如果两个类具有相同的名称,并且它们是从不同的类加载器加载的,则不能保证它们表示相同的类文件 如果不是这样的话,它也会带来安全风险,因为您可能会欺骗JavaAPI类。您可以创建自己版本的java.lang.String,使用不同的类加载器加载它,并获得java.lang中其他类的特权(例如,可以查看包私有字段)
通过名称和类装入器唯一标识类还有许多其他优点。尽管当代码抛出一个ClassCastException并且这些类具有相同的名称时看起来有点奇怪。为什么使用双斜杠?com//StaticClass.class,也是一个类加载器,在类名的末尾不需要.class。@MeBigFatGuy:我想这是类文件的相对路径,因为asela38在ILoader类中读取相同的路径。它只是类的位置,所以类加载器可以加载它,这里我使用了一个自定义类加载器(这里存在两个StaticClass类实例,它们从两个独立的类加载器(ILoader(自定义的)和sun.misc.Launcher$AppClassLoader(从java.class.path加载类))加载)解决此问题的正常方法是使用一个可供当前类加载器使用的接口并使用该接口。实现类可以位于不同的类加载上下文中,但您仍然可以通过公共接口使用它。
package com;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ILoader extends ClassLoader {
public ILoader() {
super(null);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
File file = new File(name);
byte[] bytes = new byte[(int)file.length()];
try {
new FileInputStream(file).read(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return super.defineClass("com.StaticClass",bytes, 0, bytes.length);
}
}
sun.misc.Launcher$AppClassLoader@133056f
com.ILoader@1ac3c08
StaticClass s = (StaticClass)newInstance2;