intermediate
Inheritance and polymorphism
Use inheritance for true subtype relationships and polymorphism to call behavior through a shared contract without branching on concrete types.
Inheritance models is-a subtyping: `Square extends Rectangle` only if the subtype truly honors the parent contract (LSP). Polymorphism lets callers use a shared interface—`Notifier`—without branching on concrete classes; runtime dispatch invokes the right `send` implementation.
Prefer shallow hierarchies; deep trees couple unrelated changes and encourage override surprises.
On interviews: give a valid polymorphism example and a classic LSP violation (e.g., square-rectangle).
Common pitfalls: inheritance for code reuse only, overriding methods that break parent expectations, and `instanceof` chains instead of polymorphic calls.
The trade-off is concise shared behavior versus fragile subtype hierarchies—composition often wins.
Checklist:
- Use inheritance for true subtyping.
- Call through abstractions, not concrete types.
- Check substitutability before extending.