Understanding Java Static Variable and Static Block Initialization Order
This article explains how Java initializes static variables and static blocks, demonstrates the order with ThreadLocal hash‑code generation examples, analyzes class loading rules, and summarizes the impact on object instantiation and inheritance hierarchies.
When reading the ThreadLocal source, a snippet shows how a unique hash code is generated for each thread using a static AtomicInteger and a constant HASH_INCREMENT (0x61c88647), which is related to the Fibonacci sequence and the golden ratio.
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}The focus then shifts to the order in which static fields (variables and blocks) are loaded, questioning whether the four lines of code are executed top‑to‑bottom during class initialization. The answer is “No”.
A revised example class Static01 adds a constructor that prints the generated hash code and separates static variable and static block initializations:
public class Static01 {
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = getIncr();
public Static01(){
System.out.println("threadLocalHashCode::" + threadLocalHashCode);
}
private static int getIncr() {
return 0x61c88647;
}
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
public static void main(String[] args) {
new Static01();
}
}Debugging reveals the execution sequence: (1) the new keyword triggers class initialization, (2) static variable nextHashCode is initialized, (3) static variable HASH_INCREMENT is initialized, (4) instance field threadLocalHashCode is initialized, and finally the constructor prints the hash value.
Key observations include:
Static members must be initialized before any object is created, and they follow a defined order.
Instance fields are initialized before the body of the constructor runs.
When inheritance is involved, parent class static members, then parent instance members, then parent constructor execute before the child’s corresponding steps.
Static blocks are executed only once, can only access static members, and cannot use this . Adding two static blocks demonstrates their sequential execution:
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
static{
System.out.println("Static Block 1");
}
private static final int HASH_INCREMENT = getIncr();
static{
System.out.println("Static Block 2");
}The compiled class file places all static initializations inside a single static {} block, preserving the original source order, which explains why static variables and static blocks run in the order they appear.
According to the JVM specification (e.g., "Deep Understanding of the Java Virtual Machine"), a class is initialized immediately in five situations, such as encountering new , getstatic , putstatic , or invokestatic bytecode instructions, reflective calls, superclass initialization, JVM startup with a main class, and dynamic language support in JDK 1.7.
In summary:
Static fields (variables and blocks) are loaded sequentially and only once.
Before an object is instantiated, all static members are initialized.
The typical initialization order is: parent static members → child static members → parent instance members → parent constructor → child instance members → child constructor.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.