In object-oriented programming, understanding class loading and initialization is essential for debugging object state. In Java, when you instantiate a subclass using new SubClass(), the JVM does not simply trigger the subclass constructor.
Instead, a strictly orchestrated cascade of static initialization blocks, instance initialization blocks, and constructors executes across the entire parent-child hierarchy. This initialization sequence is a common topic in technical interviews, as it tests your understanding of class loaders, memory allocation, and object state safety. By ensuring that parent class fields and behaviors are fully initialized before subclass construction begins, Java guarantees object-oriented integrity. In this guide, we will trace the exact execution flow of static and instance initialization blocks under inheritance.
To visualize this hierarchy, imagine constructing a massive Sports Complex (acting as the Parent class) that contains a specialized indoor Swimming Pool Center (acting as the Child subclass).
- Static Blocks (The Infrastructure): Before any guest can enter, the construction crew must lay down the fundamental infrastructure. First, they pour the foundation for the main complex (Parent static block). Then, they lay the filtration systems and piping for the pool (Child static block). This class loading phase happens exactly once, before any guest arrives.
- Instance Blocks (Guest Check-In): When a guest visits the complex to swim:
- First, they must check in at the main sports complex ticket lobby (Parent instance block).
- Next, they enter the pool's locker room to change (Child instance block).
Strict Initialization Sequence Rules
When instantiating a subclass, the JVM follows a four-step execution hierarchy:
- Static Initializers (Parent first, then Child): When the class loader loads the classes, all static initialization blocks run once in order of inheritance, from the top superclass down to the subclass.
- Instance Initializers (Parent first): Right before a constructor executes, the instance initialization blocks for that class run. The JVM processes the parent class first, calling the parent instance block.
- Parent Constructor: The parent class constructor runs, establishing the superclass state.
- Subclass Initializers & Constructor: Finally, the child instance blocks execute, followed by the child constructor body itself.
The Inheritance Code Structure
Let's look at a class layout with static and instance blocks on both Parent and Child classes:
class Parent {
static {
System.out.println("Parent static block");
}
{
System.out.println("Parent instance block");
}
}
class Child extends Parent {
static {
System.out.println("Child static block");
}
{
System.out.println("Child instance block");
}
}
public class MockInterview {
public static void main(String[] args) {
new Child(); // Instantiate Child
}
}
Tracing the Console Output
When the program executes new Child(), here is the exact order of logs printed to the console:
Parent static block— Runs when the Parent class is loaded. Static blocks always run first, starting from the top of the inheritance chain.Child static block— Runs when the Child class is loaded.Parent instance block— Runs because Parent constructor initialization begins. Instance blocks execute right before the constructor body.Child instance block— Runs because Child constructor initialization begins, after the Parent setup finishes.
Conclusion & Best Practices
Understanding this execution flow is critical when designing complex inheritance hierarchies, particularly when subclass state depends on parent fields. By relying on Java's strict parent-first initialization order, you can safely initialize configuration parameters, register hooks, and avoid runtime NullPointerException errors caused by uninitialized parent states.