How is the Classloader for a class chosen?

Small intro

As you already know, by default Java uses the bootstrap classloader and the system classloader. The first is responsible for loading bootstrap classes (its classpath contains artifacts such as rt.jar) and the second is responsible for holding your application's classpath. Usually the classpath either defined in your environment variable or given at JVM start using the -cp argument.

The answer

The class com.example.SomeClass will be loaded by your custom classloader Custom only if one of two things happen: either you define your custom classloader at startup to be used as system classloader or during running time you explicitly load the class through it.

A bit more about each option:

  • At application start-up: you can define when starting a JVM instance that instead of using Java's default system class loader you want to use your own. To do so, simply call java with the following environment variable defined:

    -Djava.system.class.loader=my.tests.classloaders.Custom
    

    In this case what happens is that all classes from your application in that JVM instance will actually be loaded by Custom class loader.

  • During runtime: you can at runtime load a class with your custom class loader. This is achieved creating an instance of your custom class loader and loading your class from it

         ClassLoader classloader = new CustomClassLoader();
         Class someClass = classloader.loadClass("com.example.SomeClass");
    

Like @Noofiz said in his answer once you have one class loaded all referenced classes that are required and not yet loaded are loaded through the associated class loader. So, if you load one class with your custom class loader all referenced classes will also be loaded through it. When loading all classes you can do whatever you want, log which classes are being loaded, delegate to parent class loader, load the classes by yourself...

Some extra info

Usually the best way to implement a custom class loader is to use the delegation model as you mentioned. This is because a class is actually defined not only by the classes' bytecode but also by its class loader, which means that a class loaded by two different class loaders won't be the same class.

This means that when your custom class loader is delegating to its parent you're making sure that class is available to a wider scope. Most of the time this will be what you want, but not always.

If for some reason you want class isolation then your custom class loader might be implemented the other way around. First it tries to load the class by itself and only if it doesn't find the class (or is a JVM system class or any other classes you might want to skip) delegates it to its parent. For example, web application containers work this way, allowing context redeploy (basically they discard the class loader and create a new one loading everything again) and full class isolation between web apps.

As I already said, handling class loading is not trivial at all and either you really know what you are doing or you'll certainly find yourself in some weird voodoo troubles.

Maybe already way too off topic, but if you wanna get a bit more hands on regarding class loaders and isolation you can check an old open source project called classworlds. Even though this project is old I'm suggesting it because it's a small project, filled with knowledge about class loading mechanisms which you can easily dive into.


Each class is requested in some method for the first time, every method is a part of some class, which was already loaded and has it's classloader defined. So when a new class is required, it's looked up throug curent method's class's classloader. If a class is loaded through custom class loader, it becomes base classloader for all classes loaded by method of such class. JVM specification does not define how to resolve classes statically (load all graph at start up), or dynamicaly (when first time requested). But static loading would take too long so its not used, and we recieve ClassNotFoundError when application is already running. Class and Interface Resolution