100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace

Liskov Substitution Violation: A Concrete Example

A concrete Liskov Substitution Principle violation example — Square vs Rectangle in Java — with explanation and the correct fix.

mediumQ149 of 226 in Object Oriented Programming Est. time: 6 minsLast updated:
Open Code Lab

Expected Interview Answer

A classic Liskov Substitution Principle violation is a Square class extending a Rectangle class: because setting a Square’s width must also change its height (and vice versa) to keep it square, substituting a Square wherever a Rectangle is expected breaks code that independently sets width and height and then asserts the resulting area.

The Liskov Substitution Principle requires that objects of a subtype be replaceable with objects of the supertype without altering the correctness of the program. In the Square-Rectangle case, Rectangle exposes setWidth() and setHeight() as independent operations, but Square cannot honor that contract while staying square — changing one dimension must silently change the other, violating the caller’s reasonable expectation that setWidth() leaves height untouched. Client code written and tested against Rectangle (e.g. "set width to 5, set height to 4, expect area 20") produces a wrong result when a Square is substituted in, even though Square is mathematically a specialization of Rectangle. The fix is usually to model both as implementations of a common Shape interface exposing only area(), rather than making Square inherit Rectangle’s mutable, independent setters.

  • Surfaces hidden behavioral assumptions baked into base-class contracts
  • Prevents subclasses from silently breaking client code
  • Guides better modeling (immutable shapes or a shared interface instead of forced inheritance)
  • Improves confidence that polymorphic substitution is actually safe

AI Mentor Explanation

Imagine a Bowler base class that guarantees “you can independently set the length and line of a delivery,” and a SpinBowler subclass that, for physical reasons, must always change the line whenever the length changes. Any coaching drill written against Bowler that sets length then checks the line stayed fixed will fail the moment a SpinBowler is substituted in, even though a spin bowler is clearly a kind of bowler. That mismatch between the base class’s promised independent behavior and the subclass’s forced coupling is exactly a Liskov Substitution violation.

Step-by-Step Explanation

  1. Step 1

    State the base class contract

    Identify what callers can safely assume about the base type’s behavior (e.g. setWidth doesn’t affect height).

  2. Step 2

    Find the subclass constraint

    Locate a rule the subtype must enforce that the base type never promised (e.g. width must equal height).

  3. Step 3

    Show client code breaking

    Write code against the base type that produces a wrong result only when the subtype is substituted in.

  4. Step 4

    Propose the fix

    Model both types via a shared, weaker interface (e.g. Shape.area()) or make the objects immutable instead of forcing inheritance.

What Interviewer Expects

  • A concrete example, most commonly Square-Rectangle
  • Explanation of exactly which base-class contract is broken
  • Client code (or a description of it) that demonstrates the wrong behavior
  • A sensible fix, such as a shared interface or immutability

Common Mistakes

  • Only naming Square-Rectangle without explaining WHY it violates LSP
  • Confusing LSP violations with simple compile errors (LSP violations often compile fine and fail at runtime/logically)
  • Not proposing any fix
  • Assuming any inheritance of a “special case” is automatically an LSP violation without checking the contract

Best Answer (HR Friendly)

A Liskov Substitution violation happens when a subclass technically extends a base class but cannot be swapped in for it without breaking things. The classic example is Square extending Rectangle: a Rectangle lets you set width and height independently, but a Square can’t honor that without breaking its own squareness, so code written for Rectangle gives the wrong answer when you hand it a Square instead.

Code Example

Square-Rectangle LSP violation
class Rectangle {
    protected int width, height;
    void setWidth(int w) { this.width = w; }
    void setHeight(int h) { this.height = h; }
    int area() { return width * height; }
}

class Square extends Rectangle {
    @Override
    void setWidth(int w) { width = w; height = w; } // forces height too
    @Override
    void setHeight(int h) { width = h; height = h; } // forces width too
}

// Client code written and tested against Rectangle:
Rectangle r = new Square(); // substituting Square for Rectangle
r.setWidth(5);
r.setHeight(4);
System.out.println(r.area()); // expected 20, actually 16 -- LSP violated

Follow-up Questions

  • How would you redesign Square and Rectangle to avoid this violation?
  • What is the difference between an LSP violation and a compile-time type error?
  • Can you think of another classic LSP violation besides Square-Rectangle?
  • How does LSP relate to preconditions and postconditions in a contract?

MCQ Practice

1. In the Square-Rectangle example, what exactly breaks the Liskov Substitution Principle?

Rectangle callers assume setWidth and setHeight are independent; Square cannot honor that while staying square, breaking substitutability.

2. What is a common fix for the Square-Rectangle LSP violation?

A shared, weaker interface avoids forcing Square to honor a Rectangle-specific mutable contract it cannot satisfy.

3. LSP violations typically manifest as?

LSP violations are usually behavioral: the code compiles fine but produces wrong results once the subtype replaces the supertype.

Flash Cards

Classic LSP violation example?Square extending Rectangle, since Square cannot honor independent width/height setters.

What does LSP require?Subtypes must be substitutable for their supertype without altering program correctness.

Typical fix?Use a shared, weaker interface (e.g. Shape.area()) instead of forcing inheritance.

How does the violation manifest?Client code written against the base type produces a wrong result when the subtype is substituted in.

1 / 4

Continue Learning