Class Loading Phases: Load, Link, Initialize
Walk through loading, verification, preparation, resolution, and initialization of classes.
Class Loading Phases: Load, Link, Initialize is a free Java Academy lesson on CoddyKit. This is lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, and your progress syncs across the web and the CoddyKit app. The Java Academy course includes 4 lessons in total.
The Class Loading Lifecycle
A Java class goes through three phases before it can be used: Loading (find and read the bytecode), Linking (verify, prepare, resolve), and Initialization (run static initializers).
Phase 1: Loading
The ClassLoader reads the .class file (from filesystem, JAR, network, or generated bytecode) and creates a Class<?> object in the heap representing it.
// Trigger loading explicitly:
Class<?> c = Class.forName("com.example.MyService");
// The JVM delegates to the appropriate ClassLoader to find and load MyService.classPhase 2a: Verification
The bytecode verifier checks that the loaded bytecode is structurally valid, type-safe, and follows JVM spec rules. Invalid bytecode (e.g., manipulated with ASM incorrectly) causes VerifyError.
Phase 2b: Preparation
The JVM allocates memory for static fields and sets them to their default values (0, false, null). Static initializers have NOT run yet at this stage.
public class Config {
static int timeout = 30; // after preparation: timeout = 0 (default)
static String host = "db"; // after preparation: host = null
// Both get their real values only after Initialization
}Phase 2c: Resolution
Symbolic references (class names, method signatures) in the constant pool are replaced with direct references (pointers) to the actual classes and methods. May be deferred (lazy resolution).
Phase 3: Initialization
Static initializers (static {} blocks) and static field assignments run in textual order. This is when timeout = 30 and host = "db" actually execute.
public class Config {
static int timeout;
static String host;
static {
timeout = Integer.parseInt(System.getenv("TIMEOUT"));
host = System.getenv("DB_HOST");
System.out.println("Config initialized");
}
}Class Initialization Triggers
Initialization runs on first: (1) instance creation, (2) static field access (non-constant), (3) static method call, (4) reflection via Class.forName() (with initialize=true), (5) subclass initialization.
// forName with initialize=false skips static initializers:
Class<?> c = Class.forName("com.example.MyService", false, loader);The <clinit> Method
The JVM generates a <clinit> method (class initializer) from all static initializers and static field assignments. It runs exactly once and is thread-safe — the JVM guarantees mutual exclusion.
ExceptionInInitializerError
If a static initializer throws an exception, the JVM wraps it in ExceptionInInitializerError. Subsequent attempts to use the class throw NoClassDefFoundError.
static {
if (System.getenv("DB_URL") == null)
throw new RuntimeException("DB_URL not set"); // wrapped in ExceptionInInitializerError
}Static Initialization Order
Static initializers run in textual order. Circular class dependencies during initialization can cause partially initialized classes — a known gotcha with the Initialization-on-Demand Holder pattern.
class A {
static final int X = B.Y + 1; // accesses B before B is initialized!
}
class B {
static final int Y = A.X + 1; // circular!
}Observing Class Loading
Enable class loading log output with -Xlog:class+load=info (JVM 9+) to see which classes are loaded, from where, and by which ClassLoader.
// JVM flag:
// java -Xlog:class+load=info:file=classload.log MyApp
// Output lines like:
// [info][class,load] com.example.MyService source: file:///app/app.jarQuick Check
During which phase do static initializers execute?
Recap
Load: read bytecode. Link: verify → prepare (zero defaults) → resolve (symbolic refs). Initialize: run <clinit>. Initialization is triggered by first use and is thread-safe. Circular dependencies during init cause subtle bugs.
Learn Java with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 104
- Lessons
- 374
Frequently Asked Questions
Is the “Class Loading Phases: Load, Link, Initialize” lesson free?
Yes — the full text of “Class Loading Phases: Load, Link, Initialize” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO. The Java Academy course includes 4 lessons in total.
What will I learn in “Class Loading Phases: Load, Link, Initialize”?
Walk through loading, verification, preparation, resolution, and initialization of classes. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 1 of 4.
How long does the “Class Loading Phases: Load, Link, Initialize” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Class Loading Phases: Load, Link, Initialize
- ClassLoader Hierarchy and Custom Loaders
- Inspecting Bytecode with javap
- JIT Compilation and Tiered Compilation