Liskov Substitution Principle Explained with Java Example
Explore the Liskov Substitution Principle in Java with a hands-on example. See how correct inheritance ensures predictable, bug-free behavior.
Liskov Substitution Principle (LSP)

The L in the SOLID principles stands for the Liskov Substitution Principle. By the end of this chapter, you'll be able to confidently answer:
-
What is the Liskov Substitution Principle?
-
Why do we need it? (What problems arise if we don’t follow it?)
-
How do we apply it in real-world code?
What is the Liskov Substitution Principle?
If S is a subclass of T, then objects of type T should be replaceable with objects of type S without breaking the correctness of the program.
I know, this definition might feel a bit confusing at first 😅 — so let’s break it down with a relatable example.

Let’s say we have a base class Document with methods to open, save, and print the document. We also have some subclasses for specific document types and one of the subclass (TextDocument) violates LSP.
What's the problem?
Let’s revisit the definition:
Subclasses should be replaceable for their parent class without breaking the program.
Here, TextDocument is a Document, so replacing a Document reference with a TextDocument object should just work, right?
But it doesn’t. The program crashes at runtime with an exception. That's a violation of LSP.
Changing Behavior Is Also a Violation
Let’s say instead of throwing an exception, TextDocument just logs something:
Even though it doesn’t crash anymore, it’s still violating LSP. Why?
Because the base class promised actual printing behavior, but now the child class is silently ignoring that and logging instead — the behavior has changed. That's not okay either.
How to Achieve the Liskov Substitution Principle
To fix the earlier issue, we need to redesign the class hierarchy so that only the documents which support printing have the print() method.

Here’s what we’ve done:
-
The base
Documentclass now contains only the common operations:open()andsave(). -
We’ve created a new class
PrintableDocumentthat extendsDocumentand adds theprint()functionality. -
Any document type that supports printing — like PDF or Word — will extend
PrintableDocument. -
A document like
TextDocument, which doesn’t support printing, will simply extendDocument.
This way, we follow the LSP correctly: you can substitute a PrintableDocument wherever printing is expected, and non-printable ones (like TextDocument) don’t pretend to support printing.
This redesigned class structure keeps our program’s behavior consistent and predictable when using subclass objects in place of their parent class.