Search code examples
javajvmclassloader

why this reference is AppClassLoader rather than MyClassLoader when invoke loadClass method at the first time


I write myOwnClassLoader through extends the classLoader and override its findClass method. And meet a interesting problem:

Here is the code segment:

public class MyClassLoader extends ClassLoader {
    @Override
    public Class<?> findClass(String name) {
        byte[] bt = loadClassData(name);
        return defineClass(name, bt, 0, bt.length);
    }

    private byte[] loadClassData(String className) {
        ...
    }

    public static void main(String[] args) throws ClassNotFoundException{
       MyClassLoader myClassLoader = new MyClassLoader();
       //Class<?> clazz = myClassLoader.findClass("com.classLoader.BMW");
       Class<?> clazz = myClassLoader.loadClass("com.classLoader.BMW");
       System.out.println(clazz.getClassLoader());//////////////////
    }
}

when execute

Class<?> clazz = myClassLoader.findClass("com.classLoader.BMW");

the output meet my expectation: output:

com.classLoader.MyClassLoader@xxxxxx

but when execute

Class<?> clazz = myClassLoader.loadClass("com.classLoader.BMW");

the output go beyond my mind: output:

sun.misc.Launcher$AppClassLoader@xxxx

expect output

com.classLoader.MyClassLoader@xxxxxx

here is code segment of loadClass method in ClassLoader

 Class<?> c = findLoadedClass(name);
 if (c == null) {
    long t0 = System.nanoTime();
    try {
        if (parent != null) {
            c = parent.loadClass(name, false);
            } else {
            c = findBootstrapClassOrNull(name);
        }
   .....

I debug it and find when we invoke loadClass at the first time the parent is sun.misc.Launcher$ExtClassLoader@6aa8ceb6 that is to say this reference is sun.misc.Launcher$AppClassLoader rather than com.classLoader.MyClassLoader@xxxxxx .


I search through internet and a blog define own classLoader tell that

it will set AppClassLoader as parent of MyClassLoader in default constructor.

I check it by

System.out.println(myClassLoader.getParent());

find the parent of MyClassLoader does be AppClassLoader how it achieve this, my default constructor do nothing and was this achieve in constructor method of its parent class ClassLoader? I read its parent constructor and still cant firgure out.

Anyway it seemd this cant explain why the this is AppClassLoader rather than MyClassLoader when we first invoke loadClass method. And I guess it is because that *the classLoader of MyClassLoader is AppClassLoader but it is just a intuition I have no gist.


Everything will be appreciated.


Solution

  • Well, it’s all documented:

    ClassLoader() constructor:

    Creates a new class loader using the ClassLoader returned by the method getSystemClassLoader() as the parent class loader.

    loadClass(String):

    Loads the class with the specified binary name. … Invoking this method is equivalent to invoking loadClass(name, false).

    loadClass(String,boolean-):

    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.

    If the class was found using the above steps, and the resolve flag is true, this method will then invoke the resolveClass(Class) method on the resulting Class object.

    Subclasses of ClassLoader are encouraged to override findClass(String), rather than this method.

    This is also mentioned in the class documentation of ClassLoader:

    The ClassLoader class uses a delegation model to search for classes and resources. 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. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance.

    This logic ensures clean scoping, i.e. classes of the parent scope don’t refer to classes of a sub scope, and that there are no conflicts between classes of the same qualified name, but defined by different class loaders. Such classes may still exist in distinct scopes, but not in nested scopes. But class loaders are not enforced to follow this rule. The delegation model was introduced with Java 2.