Class Loading

From .class to Running Code

The JVM loads classes lazily: a class is loaded the first time it is needed. Loading has three phases.

Main.class ─► LOADING ─► LINKING ───────────────────────────► INITIALIZATION
             (read bytes,  verify → prepare → resolve              (run static blocks,
              create Class (bytecode   (static     (symbolic refs    assign static fields)
              object)       is safe)    defaults)   → real refs)

Class Loader Hierarchy

LoaderLoadsName
Bootstrapcore JDK classes (java.lang, java.util) — written in native codeshown as null
Platformother JDK modules (java.sql, java.xml...)platform
Application (system)your classes and jars on the classpathapp
Customplugins, hot reload (Tomcat web apps, Spring DevTools)any

Loaders use parent delegation: a loader first asks its parent, and only loads the class itself if the parent cannot. This stops anyone from replacing java.lang.String with their own class.

See It Yourself

Example

A class is initialized only when first used. Its static block runs exactly once.

public class Main {
    public static void main(String[] args) {
        System.out.println("String loaded by: " + String.class.getClassLoader());
        ClassLoader app = ClassLoader.getSystemClassLoader();
        System.out.println("System loader: " + app.getName() + ", parent: " + app.getParent().getName());
        System.out.println("java.sql.Date loaded by: " + java.sql.Date.class.getClassLoader().getName());

        System.out.println("main started, Config not used yet");
        System.out.println("Reading constant: " + Config.APP_NAME);   // compile-time constant: no init
        System.out.println("Calling method:   " + Config.timeout());  // triggers initialization
        System.out.println("Calling again:    " + Config.timeout());  // static block does not run again
    }
}

class Config {
    static final String APP_NAME = "ShopEase";      // inlined by the compiler
    private static int timeout;
    static {
        System.out.println("  [Config static block runs]");
        timeout = 30;
    }
    static int timeout() { return timeout; }
}

Output

String loaded by: null
System loader: app, parent: platform
java.sql.Date loaded by: platform
main started, Config not used yet
Reading constant: ShopEase
  [Config static block runs]
Calling method:   30
Calling again:    30

Common Errors

ErrorMeaning
ClassNotFoundExceptionloading by name at runtime failed (Class.forName("x")), jar missing
NoClassDefFoundErrorclass was present at compile time but missing at runtime, or its static init failed earlier
ExceptionInInitializerErrora static block or static field initializer threw
UnsupportedClassVersionErrorcompiled with a newer Java than the one running it (e.g. built on 21, run on 17)