In what exact order do static initializer blocks, instance initializer blocks and constructors run in Java?
The order is fixed by the language specification and it is worth being able to recite it. For a class, the static parts run once: the static field declarations and static initializer blocks execute in the order they appear in the source, when the class is initialised. The class is initialised lazily, at first active use — the first time you construct an instance, or the first time you touch a static member that requires the class to be prepared.
For each object, the instance parts run in this order. First the instance field initialisers and instance initializer blocks, interleaved in source order. Then the body of the constructor. And that whole sequence happens after the superclass constructor has completed, because the superclass must be fully built before the subclass constructor body runs.
public class Main {
public static void main(String[] args) {
System.out.println("--- touching Counter.MAX triggers class init ---");
int max = Counter.MAX;
System.out.println("Counter.MAX = " + max);
System.out.println("--- first instance ---");
Counter first = new Counter();
System.out.println("first.id = " + first.id);
System.out.println("--- second instance ---");
Counter second = new Counter();
System.out.println("second.id = " + second.id);
System.out.println("instances = " + Counter.instances);
}
}
class Counter {
static final int MAX = 100;
static int instances = 0;
static {
System.out.println("static initializer block");
}
final int id;
{
// Instance initializer: runs before every constructor body.
id = ++instances;
System.out.println("instance initializer, id=" + id);
}
Counter() {
System.out.println("constructor body");
}
}The output walks through the whole sequence. The static initializer block runs the first time the class is touched, before the first instance exists. Then for each object the instance initializer runs before the constructor body, and the second instance sees the counter continue from one to two because the static field was never reset.
Two details the output makes clear. The static block ran when Counter.MAX was read, not when the class was loaded — class loading and class initialisation are separate steps. And the instance initializer runs for every instance, not once for the class.