What is ClassLoader?
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
A ClassLoader finds class definitions and helps the JVM create their runtime Class objects. Classes are usually read from .class files, but a custom loader can obtain the bytes from another source. Classes are normally loaded when they are needed, not all at startup.
Java has a bootstrap loader for core classes, a platform loader for platform classes, and a system or application loader for application code. loadClass usually uses parent-first delegation: it checks whether the class is already loaded, asks the parent, and only then tries its own findClass.
Loading is only the first step. Linking verifies the class, prepares static fields with initial values, and resolves symbolic references when required. Initialization later runs static field initializers and static blocks on active use. Class.forName(name, false, loader) can load without requesting initialization.
For example, String.class.getClassLoader() normally returns null because the bootstrap loader defines String. Two different loaders can define the same binary name, but the JVM treats them as different types because class identity includes the defining loader. This supports plugin isolation but can also lead to surprising ClassCastException errors.
What is ClassLoader
Direct Answer
A ClassLoader finds or generates the binary definition for a named class and asks the JVM to define it. Java's built-in bootstrap, platform, and system loaders usually delegate upward before searching themselves; loading is separate from linking and class initialization.
Deep Dive & Architecture
Defining and initiating are different roles
A loader that calls the JVM's definition machinery for a class is its defining loader. A different loader can initiate the request and receive the result through delegation. Runtime class identity includes the binary name and the defining loader, so two definitions named com.example.Plugin can be incompatible types.
Class loaders in a plugin boundary
An application can give each plugin its own child loader. The child finds plugin classes while delegating shared API types to a parent. This allows two plugins to carry different private library versions, yet both can implement one interface defined by the parent. If each child also defined its own copy of that interface, casts would fail even though the source names look identical.
Loader lifetime becomes class lifetime
Classes are unloaded as part of unloading their defining loader and associated classes. A static registry, running thread, thread-context class loader, cache key, or callback can accidentally retain an old plugin loader. Then its class metadata, static fields, and related resources remain reachable after redeployment.
Resources have an extra boundary
Resource lookup resembles class lookup but is not identical in every module context. Named modules can encapsulate resources, so a visible class does not mean every resource path is freely visible. When debugging, ask separately: which loader received the request, which loader defined the type, whether delegation found a parent copy, and whether module rules permit the resource.
Code Example
class ClassLoaderRoles {
public static void main(String[] args) {
ClassLoader app = ClassLoaderRoles.class.getClassLoader();
System.out.println("application: " + app);
System.out.println("parent: " + app.getParent());
System.out.println("String loader: " + String.class.getClassLoader());
}
}
Check your understanding
Answer these without looking back at the article.
- Why does String.class.getClassLoader usually return null?
- Can two classes with the same binary name be different types?
- What is the difference between loading and initialization?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.