Skip to content

15. Class Loading, Initialization, and Object Construction

Table of Contents


In Java, understanding how classes are loaded, how static and instance members are initialized, and how constructors run — especially with inheritance — is essential for mastering the language.

This chapter provides a unified, clear explanation of:

  • How a class is loaded into memory
  • How static variables and static initializers are executed
  • How objects are created step-by-step
  • How constructors run in an inheritance chain
  • How different memory areas (Heap, Stack, Method Area) participate

15.1 Java Memory Areas Relevant to Class and Object Initialization

Before understanding initialization order, it is useful to recall the three main memory areas involved:

  • Method Area (a.k.a. Class Area) — stores class metadata, static variables, and static initializer blocks.
  • Heap — stores all objects and instance fields.
  • Stack — stores method calls, local variables, and references.

Note

Static members belong to the class and are created once in the Method Area.

Instance members belong to each object and live in the Heap.


15.2 Class Loading (with Inheritance)

When a Java program starts, the JVM loads classes on demand.

When a class is referenced for the first time (e.g., by calling new or accessing a static member), its entire inheritance chain must be loaded in memory first.

15.2.1 Class Loading Order

Given a class hierarchy:

class A { ... }
class B extends A { ... }
class C extends B { ... }

If the code executes:

public static void main(String[] args) {
    new C();
}

Then class loading proceeds in this strict order:

  • Load class A
  • Initialize A’s static variables (default → explicit)
  • Run A’s static initializer blocks (top → bottom)
  • Load class B and repeat the same logic
  • Load class C and repeat the same logic

15.2.2 What Happens During Class Loading

  • Step 1: Static variables are allocated (default values first).
  • Step 2: Explicit static initializations run.
  • Step 3: Static initializer blocks run in source order.

Note

After these steps, the class is fully prepared and may now be used (instantiated or referenced).

Warning

Accessing a static field triggers the initialization only of the class or interface that directly declares that field.

This is true even if the field is accessed using the name of a subclass, a subinterface, or a class that implements the interface.


15.3 Object Creation (with Inheritance)

When the new keyword is used, instance creation follows a strict and predictable sequence involving all parent classes.

15.3.1 Full Instance Creation Order

  • 1. Memory is allocated on the Heap for the new object (fields get default values).
  • 2. The constructor chain runs (not yet the bodies) from parent to child — the top of the hierarchy runs first, then each subclass.
  • 3. Instance variables receive explicit initializations.
  • 4. Instance initializer blocks execute.
  • 5. The constructor body runs: for each class in the inheritance chain, steps 3–5 (field initialization, instance blocks, constructor body) are applied from parent to child.

15.4 A Complete Example: Static + Instance Initialization Across Inheritance

Consider the following three-level hierarchy:

class A {
    static int sa = init("A static var");

    static {
        System.out.println("A static block");
    }

    int ia = init("A instance var");

    {
        System.out.println("A instance block");
    }

    A() {
        System.out.println("A constructor");
    }

    static int init(String msg) {
        System.out.println(msg);
        return 0;
    }
}

class B extends A {
    static int sb = init("B static var");   // call to the inherited static method init(String)

    static {
        System.out.println("B static block");
    }

    int ib = init("B instance var");    // call to the inherited static method init(String)

    {
        System.out.println("B instance block");
    }

    B() {
        System.out.println("B constructor");
    }
}

class C extends B {
    static int sc = init("C static var");   // call to the inherited static method init(String)

    static {
        System.out.println("C static block");
    }

    int ic = init("C instance var");    // call to the inherited static method init(String)

    {
        System.out.println("C instance block");
    }

    C() {
        System.out.println("C constructor");
    }
}

public class Test {
    public static void main(String[] args) {
        new C();
    }
}

Output

A static var
A static block
B static var
B static block
C static var
C static block
A instance var
A instance block
A constructor
B instance var
B instance block
B constructor
C instance var
C instance block
C constructor

15.5 Visualization Diagram

            CLASS LOADING (top to bottom)

                A  --->  B  --->  C
                |         |         |
      static vars + static blocks executed in order

-------------------------------------------------------

            OBJECT CREATION (bottom to top)

 new C() 
    |
    +--> allocate memory for C (default values)
    +--> call B() constructor
            |
            +--> call A() constructor
                    |
                    +--> init A instance vars
                    +--> run A instance blocks
                    +--> run A constructor
            +--> init B instance vars
            +--> run B instance blocks
            +--> run B constructor
    +--> init C instance vars
    +--> run C instance blocks
    +--> run C constructor

15.6 Key Rules

  • Static initialization happens once per class.
  • Static initializers run in parent → child order.
  • Instance initialization runs every time an object is created.
  • For each class in the inheritance chain, instance fields and instance blocks run before that class’s constructor body.
  • Overall, both field/instance initialization and constructors execute from parent to child.
  • Constructors always call the parent constructor (explicitly or implicitly).

15.7 Summary Table

STATIC (Class Level) INSTANCE (Object Level)
One-time-only Happens at every 'new'
Executed parent → child Instance initialization and constructors parent → child
static vars (default → explicit) instance vars (default → explicit)
static blocks instance blocks + constructor