views:

326

answers:

3

I have seen several places that "Class.getClassLoader() returns the ClassLoader used to load that particular class", and therefore, I am stumped by the results of the following example:


package test;

import java.lang.*;

public class ClassLoaders { 
    public static void main(String[] args) throws java.lang.ClassNotFoundException{
      MyClassLoader mcl = new MyClassLoader();
      Class clazz = mcl.loadClass("test.FooBar");
      System.out.println(clazz.getClassLoader() == mcl); // prints false
      System.out.println(clazz.getClassLoader()); // prints e.g. sun.misc.Launcher$AppClassLoader@553f5d07
    }
}

class FooBar { }

class MyClassLoader extends ClassLoader { }

Shouldn't the statement clazz.getClassLoader() == mcl return true? Can someone explain what I am missing here?

Thanks.

A: 

If the selfdefined classloader delegates the call to classloader of the VM, who loads the class. clazz.getClassLoader() will return this classloader.

To get into the detail: The Javadoc of the class ClassLoader provides the following explanation of the order of executed steps:

Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:

  1. Invoke findLoadedClass(String) to check if the class has already been loaded.
  2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
  3. Invoke the findClass(String) method to find the class.

As you inherited without a change the methods, this behaviour will be unchanged. Step 2 will be the one, where the class will be loaded. As you call the parameterless constructor of ClassLoader (automatically, as you didn't defined a constructor in MyClassLoader) you automatically make use of the builtin ClassLoader.

Mnementh
Actually, it first asks its parent to find the class before attempting to do it itself.
Michael Borgwardt
Michael, Java SE defines it that way, but Java EE suggests that implement class loaders that do otherwise...
Tom Hawtin - tackline
+9  A: 

Whenever you create your own classloader it will be attached in a tree-like hierarchy of classloaders. To load a class a classloader first delegates the loading to its parent. Only once all the parents didn't find the class the loader that was first asked to load a class will try to load it.

In your specific case the loading is delegated to the parent classloader. Although you ask you MyClassLoader to load it, it is the parent that does the loading. In this case it is the AppClassLoader.

lewap
adding System.out.println(clazz.getClassLoader() == mcl.getParent()); //Return true... got itproves this point quite nicely, thanks
Newtopian
+5  A: 

Citing the API doc of ClassLoader:

Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.

Michael Borgwardt
Also the example uses the no-args ClassLoader constructor: "Creates a new class loader using the ClassLoader returned by the method getSystemClassLoader() as the parent class loader." (Odd backward-compatible behaviour.)
Tom Hawtin - tackline