Search code examples
javaclassloader

Java System Class Loader is not really being replaced


Can the Java System class Loader really be replaced?

Java has a property named -Djava.system.class.loader for replacing the system class loader.

However, any class created using new, rather than .newInstance() shows AppClassLoader as its class loader.

AppClassLoader is also known as the system class loader, so it doesn't seem that any real replacing is going on.

For example, when running (Oracle Hotspot on Windows JDK 1.8)

// Run with java -Djava.system.class.loader=classLoaders.MyClassLoader Example

public class MyClassLoader extends ClassLoader {
    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    @Override
    public Class loadClass(String name) throws ClassNotFoundException {
        System.out.println("Loading class :" + name);
        return super.loadClass(name);
    }
}

class A {
}

public class Example {
    public static void main(String[] args) throws Exception {
        System.out.println(ClassLoader.getSystemClassLoader());
        System.out.println(new Example().getClass().getClassLoader());
        System.out.println(new A().getClass().getClassLoader());
    }
}

The output is:

Loading class :classLoaders.Example
classLoaders.MyClassLoader@6d06d69c
sun.misc.Launcher$AppClassLoader@58644d46
sun.misc.Launcher$AppClassLoader@58644d46

While the first instance of Example is being loaded by MyClassLoader, and the method getSystemClassLoader returns the MyClassLoader, any class created using new is loaded by the original System Class Loader, so what exactly is being replaced?


Solution

  • You are just extending ClassLoader and using super.loadClass(); So, some other real class loader is doing the actual class loading.

    Behind the scenes, the system seems to be delegating to the System class loader, after you pass on the loading work.

    Here the same question is already answered: https://stackoverflow.com/a/25493910/1364747

    1. MyClassLoader is the initiating class loader
    2. AppClassLoader is the defining class loader
    3. All classes loaded in the same package are from defining class loader (which actually loaded the first class in the package).

    A class loader L may create C by defining it directly or by delegating to another class loader. If L creates C directly, we say that L defines C or, equivalently, that L is the defining loader of C.

    When one class loader delegates to another class loader, the loader that initiates the loading is not necessarily the same loader that completes the loading and defines the class. If L creates C, either by defining it directly or by delegation, we say that L initiates loading of C or, equivalently, that L is an initiating loader of C.

    At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader. Each such class or interface belongs to a single run-time package. The run-time package of a class or interface is determined by the package name and defining class loader of the class or interface.

    Although MyClassLoader calls super.loadClass, the implementation of ClassLoader->loadClass only finds another instance, and delegates to it.

    So, the parent class implementation only passes on the job to a different instance.