为从中加载该类的对象创建引用时?

时间:2010-12-31 04:20:55

标签: java classloader

当使用Java进行一些示例编码时,我遇到了ClassCastException,从那里我将对象转换为StaticClass。谁能解释一下这里发生了什么?

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

}

package com;

public class StaticClass {

   public static final Object obj = new Object();
}

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

当代码的转换部分不存在时,由最后一个System.out给出的输出如下所示。

sun.misc.Launcher$AppClassLoader@133056f
com.ILoader@1ac3c08

2 个答案:

答案 0 :(得分:2)

当两个类加载器加载一个类时,实际上有两个类的副本。在您执行此类操作的场景中

StaticClass s = (StaticClass)newInstance2;

然后默认情况下,您的默认系统类加载器会出现在图片中以进行投射。由于newInstance2是从另一个类加载器加载的,因此它将给出一个ClassCastException。这不起作用 - 它们由JVM中的两个不同的Class对象表示,并且转换将失败。

有关详细信息,请参阅以下文章和论坛条目:

  1. http://onjava.com/pub/a/onjava/2003/11/12/classloader.html

  2. http://java.sun.com/developer/technicalArticles/Networking/classloaders/index.html

  3. http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html

  4. http://www.coderanch.com/t/380416/java/java/Loading-same-class-two-different

  5. Different classloaders cause ClassCastException when persisting data via Spring

答案 1 :(得分:0)

一个类由其完全限定名称和加载它的类加载器定义。

这是必要的,因为如果两个类具有相同的完全限定名并且在同一位置(相同的类加载器)中找到它们,则它们只是相同的。

如果两个类具有相同名称​​和,则它们是从不同的类加载器加载的,并不能保证它们代表相同的类文件。

如果不是这样,那么它也会带来安全风险,因为您可以欺骗Java API类。您可以创建自己的java.lang.String版本,使用不同的类加载器加载它并获得java.lang中其他类的特权(例如,可以查看包私有字段)。

通过名称和类加载器对类进行唯一标识,还有许多其他优点。虽然代码抛出ClassCastException并且类具有相同的名称时看起来有点奇怪。