Never call an overridable method from a constructor
The subclass override runs before its own fields exist.
Open this lesson in the learning hubKey points
- Construction runs parent-first: the superclass constructor completes before any subclass field initialiser or constructor body runs.
- If the superclass constructor calls an overridable method, the subclass override executes at that moment - against a subclass whose fields are all still at their defaults.
- The result is a null field or a zero where the code plainly assigns a value, and it looks impossible until you know the ordering.
- A
finalsubclass field is especially confusing: it appears null inside the override and non-null afterwards, which contradicts what final seems to promise. - The rule is absolute: a constructor may only call methods that are
private,staticorfinal. Anything overridable is unsafe. - The same applies to
cloneandreadObject, which also run before the object is fully constructed - and to publishingthisfrom a constructor, which lets another thread see a half-built object.
Example
public class ConstructorOverride {
static class Base {
Base() {
System.out.println(" Base constructor calls init()");
init(); // DANGEROUS: overridable
}
void init() { System.out.println(" Base.init"); }
}
static class Derived extends Base {
private final String name = "assigned in field initialiser";
private int count = 42;
Derived() {
super(); // Base() runs FIRST
System.out.println(" Derived constructor body");
System.out.println(" name = " + name);
System.out.println(" count = " + count);
}
@Override void init() {
// Runs during Base(), before ANY Derived field is assigned.
System.out.println(" Derived.init name = " + name
+ ", count = " + count + " <- fields not yet set");
}
}
// SAFE: nothing overridable is called during construction.
static class SafeBase {
SafeBase() { setUp(); }
private void setUp() { System.out.println(" SafeBase.setUp (private - cannot be overridden)"); }
}
static class SafeDerived extends SafeBase {
private final String name = "set normally";
SafeDerived() { super(); System.out.println(" SafeDerived name = " + name); }
}
public static void main(String[] args) {
System.out.println("Constructing Derived:");
new Derived();
System.out.println();
System.out.println("Note the final field read as null inside init(),");
System.out.println("and non-null a moment later. Both are correct.");
System.out.println();
System.out.println("Constructing SafeDerived:");
new SafeDerived();
System.out.println();
System.out.println("RULE: from a constructor, call only private,");
System.out.println(" static or final methods.");
}
}
The superclass constructor runs first, so an overridden method it calls sees subclass fields at their defaults - even final ones.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the OOP course, and every lesson in it is listed on the OOP contents page.