SOLID principles
intermediateLiskov Substitution Principle (LSP)
Subtypes must be substitutable for their base types without altering correctness.
The Liskov Substitution Principle states that objects of a subtype must be usable anywhere the base type is expected, without altering the correctness of the program. Inheritance promises an "is-a" relationship; LSP makes that promise behavioural, not merely structural. It is not enough for a subclass to compile in place of its parent — it must honour the parent's contract so that code written against the parent keeps working when handed the child.
A USB port promises power and data. Any USB device should work in any USB port without changing the host's expectations. A device that says "I'm USB" but only works upside down on Wednesdays violates the contract.
Key Concepts
1
The famous counter-example is Square extends Rectangle. A rectangle lets you set width and height independently; a square cannot without violating its own invariant, so overriding the setters to keep the sides equal breaks any client that sets width and height separately and expects them to stay that way. The subtype passes the compiler but fails the behavioural contract. Concretely, honouring LSP means a subtype must not strengthen preconditions (demand more of callers than the parent did), must not weaken postconditions (deliver less than the parent promised), must preserve the parent's invariants, and must not throw new checked exceptions the parent's contract didn't allow. A method that throws UnsupportedOperationException for an inherited operation — like an immutable collection's add — is a classic LSP violation hiding in the standard library.
Square extends RectangleUnsupportedOperationExceptionadd
2
For interviews, the key insight is that LSP exposes when inheritance is the wrong tool. If a subclass keeps having to disable, contradict, or throw on inherited behaviour, the "is-a" relationship is an illusion and the design should favour composition over inheritance, or refactor the hierarchy so the shared abstraction only promises what every subtype can truly deliver. LSP is what makes the Open/Closed Principle safe: you can only extend by substitution if substitutes actually behave.