Never call an overridable method from a constructor

OOP · lesson 41 of 43 · 6 min read

The subclass override runs before its own fields exist.

Open this lesson in the learning hub

Key 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 final subclass 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, static or final. Anything overridable is unsafe.
  • The same applies to clone and readObject, which also run before the object is fully constructed - and to publishing this from 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.