Search code examples
javareflectionclassloader

Why A.class.getClassLoader() does not return the loader used by loader.loadClass("A")


In this test case we are loading a class A through a specific class loader instance, i.e. GwClassLoader. However, the A.class.getClassLoader() does not retrieve that class loader? This is the test case:

class A{
  static {
    ClassLoader loader = A.class.getClassLoader();
    System.out.println("A.<cinit>: " + loader);
  }
}

class ClassLoaderGw extends ClassLoader { }

public class App {
  public static void main(String [] args)  throws ClassNotFoundException,  InstantiationException,  IllegalAccessException {
    ClassLoaderGw loader = new ClassLoaderGw();
    System.out.println("Main: " + loader);
    Class<?> klass = loader.loadClass("A");
    Object obj = klass.newInstance();
  }
}

And, this is the output of running the class App:

Main: ClassLoaderGw@6d06d69c
A.<cinit>: sun.misc.Launcher$AppClassLoader@73d16e93

How can I get the instance of GwClassLoader inside the static constructor of the class A?


Solution

  • The ClassLoaderGw simply extends ClassLoader without overriding any methods. Therefore, it will follow the strategy of the standard loadClass method (javadoc) ... which is to delegate to the parent classloader first.

    In this case, your A class is on the parent classloader's classpath, so that is what will load it.

    The final piece of the puzzle is that getClassLoader() returns the classloader that actually loaded the class, not the classloader that you asked to do the loading.


    How can I get the instance of GwClassLoader inside the static constructor of the class A?

    Basically, you can't ... unless GwClassloader was responsible for loading the class A.

    Could you make it work? Well ... if you used a different class loading strategy you could. Maybe. If GwClassloader was able to find the bytecodes for A and call defineClass itself, then it would be the classloader for A.

    However, you need to worry about the possibility that class A could also be loaded by the parent classloader. If that happens you could have two distinct A types in existence at the same time. This can lead to class cast exceptions in unexpected places.