Polymorphism pitfalls & constructors
◈ 5 cardsConstructor call order under inheritance, the calling-an-overridable-method-in-a-constructor trap, and what is NOT polymorphic.
The order of construction under inheritance
When you create a subclass object, Java builds it base-first. The exact order is:
- The superclass constructor runs (recursively, up to
Objectfirst). - The subclass's instance field initializers run, in source order.
- The rest of the subclass constructor body runs.
This base-first rule sets up the famous trap.
Worked example: a constructor that calls an overridable method
class Glyph {
Glyph() { draw(); } // calls an overridable method!
void draw() { System.out.println("Glyph.draw"); }
}
class RoundGlyph extends Glyph {
private int radius = 5; // field initializer
@Override void draw() {
System.out.println("RoundGlyph.draw, radius = " + radius);
}
}
Now new RoundGlyph(); prints:
RoundGlyph.draw, radius = 0
Why 0, not 5? Trace it:
RoundGlyph's construction begins; the implicitsuper()runsGlyph()first.- Inside
Glyph(),draw()is called. Becausedraw()is overridden and dispatch is dynamic, it runsRoundGlyph.draw()— the subclass version — even though we are still inside the superclass constructor. - But
RoundGlyph's field initializer (radius = 5) has not run yet — it runs aftersuper()returns. Soradiusstill holds its default value,0.
The overridden method runs against a half-built object. The lesson: never call an overridable (non-final, non-private, non-static) method from a constructor. Either make such helper methods final/private, or don't call them during construction.
What is NOT polymorphic
Late binding applies only to overridable instance methods. Three things resolve by the static (declared) type instead, and the exam loves to test this:
- Fields are not polymorphic. A field reference is resolved by the declared type. If both
SuperandSubdeclare a fieldx, thenSuper ref = new Sub(); ref.xreadsSuper'sx(the field is hidden, not overridden). staticmethods are not polymorphic. They are hidden, not overridden, and bound to the declared type.privatemethods are not overridable at all. A subclass method with the same name is a new, independent method; the superclass's own code keeps calling the superclass's private version.