Search code examples
javaclassloader

When creating a reference for an object where that class is loaded from?


When doing some sample coding with Java I came across ClassCastException, from where I cast the object to StaticClass. Can anyone explain what has happened here?

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

output which was given by last System.out when the casting part of the code not existed is as below.

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

Solution

  • When two class loaders load a class, you actually have two copies of the class. In your scenario when you do something like this

    StaticClass s = (StaticClass)newInstance2;
    

    Then by default your default system class loader comes into picture for casting. Since the newInstance2 is loaded from another classloader therefore it will give a ClassCastException. This will not work - they are represented by two different Class objects inside the JVM and the cast will fail.

    For more details refer to the following articles and forum entries:

    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