skip to content
everything.oop.constructorsAndInitOrder

constructors and init order

the exact order fields, initializers and constructors run in.

chapter
chapter 03.02
reading time
6 min read

new Child() runs things in a fixed order. first, static init for Parent, then Child (once per class, ever). then the object is allocated with every field zeroed. then the constructors chain up through this(...) and super(...) to Object, and on the way back down each class runs its field initializers and init blocks, then the rest of its constructor body.

parents first. always.

the picture

you know how a subclass constructor can't touch anything until super(...) returns? there's a reason, and it's the order.

think of a two-storey house. you hire the contractor for the top floor (Child), but the first thing he does is call the ground-floor contractor (Parent) and wait. the ground floor gets finished completely (its fields, its init blocks, its constructor body) before anyone lays a single brick upstairs. the top-floor contractor got called first and walks out last.

which =
call =
ParentChild
1
static fields + static blocks, top to bottomonce per class, ever
2
static fields + static blocks, top to bottomonce per class, ever
3
allocate one object. every field, Parent's and Child's, is zeroed
4
Child() starts: this("rex")
5
Child(String) starts: super()
6
Parent() starts: super() → Object()
7
field initializers + init blocks, in source order
8
rest of the Parent() body
9
field initializers + init blocks, in source orderonly in the constructor that called super()
10
rest of the Child(String) body
11
rest of the Child() bodyfirst to start, last to finish
flip between the first and second new: the static rows only ever happen once per class. then call new Child("rex") directly and watch the this(...) hop disappear. the allocation always comes before any constructor code.

constructors, quickly

a constructor has the class's name and no return type. it's not really a method: you can't call it on an object, only through new, this(...) or super(...).

Point.java
class Point {
    final int x, y;
 
    Point(int x, int y) {   // the real one
        this.x = x;
        this.y = y;
    }
 
    Point() {
        this(0, 0);         // delegate to the real one
    }
}
this(...)
call another constructor of the same class. handy for defaults: every path ends up in one "real" constructor.
super(...)
call the parent's constructor. if you don't write either, javac quietly inserts super().
default constructor
if a class declares no constructor at all, javac adds a no-arg one that just calls super(). declare any constructor and you lose it.
init block
a bare { ... } in the class body. runs for every object, as if pasted into each constructor that calls super(...).
static block
static { ... }. runs once, when the class is initialized.

walk through it

here's a real program that prints at every single step. two classes, statics, fields, init blocks, a this(...) and two new Child()s. the stack shows the constructor chain growing and shrinking.

Main.java next to run
  1. 1class Parent {
  2. 2 static String ps = Main.log("Parent static field");
  3. 3 static { Main.log("Parent static block"); }
  4. 4
  5. 5 String pf = Main.log("Parent field");
  6. 6 { Main.log("Parent init block"); }
  7. 7
  8. 8 Parent() {
  9. 9 super();
  10. 10 Main.log("Parent() body");
  11. 11 }
  12. 12}
  13. 13
  14. 14class Child extends Parent {
  15. 15 static String cs = Main.log("Child static field");
  16. 16 static { Main.log("Child static block"); }
  17. 17
  18. 18 String cf = Main.log("Child field");
  19. 19 { Main.log("Child init block"); }
  20. 20
  21. 21 Child() {
  22. 22 this("rex");
  23. 23 Main.log("Child() body");
  24. 24 }
  25. 25
  26. 26 Child(String name) {
  27. 27 super();
  28. 28 Main.log("Child(String) body");
  29. 29 }
  30. 30}
  31. 31
  32. 32public class Main {
  33. 33 static String log(String what) {
  34. 34 System.out.println(what);
  35. 35 return what;
  36. 36 }
  37. 37
  38. 38 public static void main(String[] args) {
  39. 39 new Child();
  40. 40 log("--- again");
  41. 41 new Child();
  42. 42 }
  43. 43}
stdout
·
stack
main
no locals yet
heap
nothing allocated yet.

main is about to say new Child(). but Child has never been used, so before any object exists, its classes get initialized.

step 1/18
step 6 is the one to stare at: the object already exists, pf and cf both null, and three constructor frames pile up before a single initializer runs. then compare stdout before and after --- again.

see? the static lines print once (scrub to the last step and read stdout). everything else prints twice, in exactly the same order. and Child(), the constructor new actually called, is the last one to print.

predict the output
java
class A {
    { IO.print("a "); }
    A() { IO.print("A "); }
    static { IO.print("sA "); }
}
 
class B extends A {
    static { IO.print("sB "); }
    B() { IO.print("B "); }
    { IO.print("b "); }
}
 
void main() {
    new B();
    new B();
}
one level deeper:where the initializers actually go+

there's no "run the initializers" step in the JVM. javac pastes field initializers and init blocks into every constructor that calls super(...), right after that call. constructors that start with this(...) don't get a copy, which is why the initializers run once per object, not once per constructor. javap -c Child on the program above:

text
Child();
   aload_0
   ldc "rex"
   invokespecial Child.<init>(String)   // this("rex"). no initializers here
   ldc "Child() body" ...
 
Child(java.lang.String);
   aload_0
   invokespecial Parent.<init>()        // super()
   ldc "Child field" ... putfield cf    // the field initializer, pasted in
   ldc "Child init block" ...           // the init block, pasted in
   ldc "Child(String) body" ...

static initializers get the same treatment, collected in source order into one hidden method called <clinit>, which the JVM runs when the class is first initialized. more in class loading.

the trap: overridable calls in a constructor

the parent's constructor runs before the child's fields are set. so if the parent calls a method the child overrides, the child's code runs against a half-built object.

Main.java
class Base {
    Base() {
        describe(); // runs Pet's version, before Pet is ready
    }
 
    void describe() {
        IO.println("a base");
    }
}
 
class Pet extends Base {
    final String name;
 
    Pet(String name) {
        this.name = name; // too late: super() already ran
    }
 
    @Override
    void describe() {
        IO.println("a pet named " + name);
    }
}
 
void main() {
    new Pet("rex");
}
output
a pet named null

name is final and it still prints null. you just watched a final field change value. kinda cursed.

java 25: statements before super()

since java 25+ a constructor can run code before super(...) (flexible constructor bodies, JEP 513). you still can't read this, call instance methods or touch super there, but you can assign your own fields. so the fix is to set name first:

Main.java
class Base {
    Base() {
        describe();
    }
 
    void describe() {
        IO.println("a base");
    }
}
 
class Pet extends Base {
    final String name;
 
    Pet(String name) {
        this.name = name; // before super(): allowed since java 25
        super();
    }
 
    @Override
    void describe() {
        IO.println("a pet named " + name);
    }
}
 
void main() {
    new Pet("rex");
}
output
a pet named rex

the prologue is also the right place for validation (throw before the parent does any work). what it can't do is read the object:

Main.java
class Dog extends Animal {
    String tag = "dog";
 
    Dog(String name) {
        IO.println(tag);
        super(name);
    }
}

error: cannot reference tag before supertype constructor has been called

keylines
  • static init runs once per class, parent before child, on first use.
  • the object exists, all zeroed, before any constructor code runs.
  • constructors chain up first (this(...), super(...)), then do their work on the way back down.
  • field initializers and init blocks run right after super(...) returns, in source order.
  • never call an overridable method from a constructor. in java 25 you can at least set your fields before super().