Understanding Initialization Order: Static Blocks, Instance Blocks, and Constructors in Java

When a Java class is loaded and used, its initialization blocks execute in a specific sequence: static initialization block, instance initialization block (construction code block), then constructor. However, there are nuances when dealing with final static fields or nested classes.

Consider the folllowing example. We define classes ClassA, ClassB, and ClassC, where ClassC extends ClassB. Each class contains a static initializer, an instance initializer, and a constructor that print messages:

public class ClassA {
    public static void main(String[] args) {
        System.out.println(ClassC.str);
    }

    static {
        System.out.println("staticClassA");
    }
    {
        System.out.println("instanceClassA");
    }
    ClassA() {
        System.out.println("constructorClassA");
    }
}

class ClassB {
    static {
        System.out.println("staticClassB");
    }
    {
        System.out.println("instanceClassB");
    }
    ClassB() {
        System.out.println("constructorClassB");
    }
}

class ClassC extends ClassB {
    public static String str = "ClassC";
    static {
        System.out.println("staticClassC");
    }
    {
        System.out.println("instanceClassC");
    }
    ClassC() {
        System.out.println("constructorClassC");
    }
}

Case 1: Accessing a static field of the subclass

When we run System.out.println(ClassC.str);, the output is:

staticClassA
staticClassB
staticClassC
ClassC

Notice that the static initializers for all classes in the hierarchy execute, even though we only accessed a static field in ClassC. This is because accessing any static member of a class triggers its initialization, and since ClassC extends ClassB, the superclass must be initialized first.

Case 2: Creating an instance of the subclass

If we create an instance of ClassC:

ClassC c = new ClassC();
System.out.println(c.str);

The output becomes:

staticClassA
staticClassB
staticClassC
ClassC
----------------------------
instanceClassB
constructorClassB
instanceClassC
constructorClassC
ClassC

Static initializers run once per class loading, while instance initializers and constructors run each time an object is instantiated. The instance initializer of the parenet runs before the child's constructor.

Case 3: Declaring the static field as final

If we change the field to public static final String str = "ClassC";, the output is:

staticClassA
ClassC
----------------------------

When the static field is a compile-time constant (primitive or String and initialized with a literal), the Java compiler inlines its value. Therefore, reading the field does not require loading the class, and the static initializers of ClassC and ClassB do not execute.

Key points:

  • Static initializers run when the class is first loaded, typically triggered by access to a static field or method, or by creating the first instance.
  • Instance initializers run before the constructor each time an instance is created.
  • Constructors run after instance initializers.
  • If a subclass is initialized, its superclass must be initialized first.
  • A final static field with a compile-time constant value does not trigger class initialization.
  • Accessing a static inner class does not cause the outer class to initialize.

Tags: java initialization Static Block constructor Instance Block

Posted on Sat, 31 Oct 2026 16:02:54 +0000 by champbronc2