OBJECT-ORIENTED FOUNDATIONS / OBJECT DESIGN BRIEF

Inheritance

Inheritance lets a class (subclass) reuse and extend another class (superclass).

BeginnerPhase 01 / Topic 4 of 7ResponsibilitiesCollaborationsExtensibility
01

Overview

Inheritance lets a class (subclass) reuse and extend another class (superclass). The subclass gets the parent's fields and methods and can override behavior. It models an 'is-a' relationship: a SavingsAccount is an Account.

Inheritance is powerful but creates the tightest coupling in OOP: subclasses depend on the parent's internals, and changes to the parent can break children (the fragile base class problem). Modern guidance is to inherit only for true is-a relationships that honor the parent's contract (Liskov Substitution), and to prefer composition for sharing behavior.

Family traits

Children inherit traits from parents automatically, including ones they may not want. You cannot pick only the useful traits, which is why inheritance should be used carefully.

02

When to use it

  • A genuine is-a relationship with a stable base contract.
  • Framework extension points designed for subclassing (Template Method).
  • Sharing implementation among closely related types in one module.
03

Where it shows up in interviews

Type hierarchies

Recognize it when: vehicle types, account types, shapes, chess pieces.

  • Design a chess game
  • Design a parking lot vehicle hierarchy
Inheritance misuse

Recognize it when: subclass disables or throws in parent methods.

  • Refactor a Square extends Rectangle
  • Refactor a deep class hierarchy
04

Where it is used in real software

Java exceptions

IOException extends Exception extends Throwable, letting catch blocks handle families of errors.

UI frameworks

Android views and older Java Swing components are built on inheritance hierarchies.

Framework base classes

Spring's AbstractController and JUnit extensions use abstract base classes as extension points.

05

Key terms

Superclass / subclass
Parent / child in the hierarchy.
Override
Replace a parent method's behavior.
super
Call the parent's constructor or method.
Fragile base class
Parent changes unexpectedly break subclasses.
final / sealed
Prevent or restrict further subclassing.
06

How it works, step by step

  1. 1
    Check the is-a test

    Is every child truly usable wherever the parent is?

  2. 2
    Put shared stable behavior in the parent

    Keep it small.

  3. 3
    Override deliberately

    Use @Override / override keyword to catch mistakes.

  4. 4
    Protect the contract

    Children must not weaken guarantees.

  5. 5
    Limit depth

    Keep hierarchies shallow (one or two levels).

07

Chess pieces

abstract class Piece { canMove(from, to, board) }

Step 1 / 4
SubclassOverrides canMove asShares from Piece
RookStraight lines, path clearcolor, position, capture rules
BishopDiagonals, path clearcolor, position, capture rules
KnightL-shape, can jumpcolor, position, capture rules
KingOne square any directioncolor, position, capture rules

NOWSubclass: Rook | Overrides canMove as: Straight lines, path clear | Shares from Piece: color, position, capture rules

A legitimate hierarchy: every piece is a Piece, and the board treats them uniformly through canMove.

08

Implementation

type Pos = { r: number; c: number }; abstract class Piece {  constructor(readonly color: "white" | "black") {}  abstract canMove(from: Pos, to: Pos): boolean;  protected delta(from: Pos, to: Pos) {    return { dr: Math.abs(to.r - from.r), dc: Math.abs(to.c - from.c) };  }} class Knight extends Piece {  canMove(from: Pos, to: Pos) {    const { dr, dc } = this.delta(from, to);    return (dr === 2 && dc === 1) || (dr === 1 && dc === 2);  }} class King extends Piece {  canMove(from: Pos, to: Pos) {    const { dr, dc } = this.delta(from, to);    return Math.max(dr, dc) === 1;  }} const pieces: Piece[] = [new Knight("white"), new King("black")];pieces.map((p) => p.canMove({ r: 0, c: 0 }, { r: 1, c: 2 })); // [true, false]
09

Complexity and performance

Method dispatchO(1) vtable lookup

Virtual call.

CouplingHighest in OOP

Child sees parent internals.

10

Trade-offs

Reuse vs coupling

Inheritance reuses code easily but ties children to the parent's implementation details.

Static vs dynamic

A class's parent is fixed at compile time; composition can swap behavior at runtime.

11

Variants and related techniques

Interface inheritance

Inherit a contract without implementation; much looser coupling.

Sealed hierarchies

Java sealed classes and TypeScript discriminated unions close the set of subtypes.

12

Common mistakes

  • Inheriting to reuse a helper method.

    Fix: Use composition or a utility instead.

  • Subclasses that throw UnsupportedOperationException.

    Fix: The child is not really an is-a; redesign the hierarchy.

  • Deep hierarchies.

    Fix: Flatten; favor interfaces and composition.

13

Interview questions

When should you use inheritance?

When there is a true is-a relationship, the subclass can be used anywhere the parent is expected without surprises, and the parent is designed for extension. Otherwise prefer composition.

What is the fragile base class problem?

Changes in a parent class, even internal ones, can break subclasses that depend on its behavior or call order, because subclasses are coupled to the parent's implementation.

14

Practice problems

ProblemDifficultyWhat it trains
Model vehicle types for a parking lotEasyIs-a checks.
Refactor Square extends RectangleMediumLSP violation.