When to use inheritance — valid use cases
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
I choose inheritance when the class really is a behavioral subtype and the base class is designed to be extended. For example, an abstract Shape with an area() contract can support Circle and Rectangle if every caller can rely on the same invariants. Another valid case is a framework base that documents callback methods.
I use the Liskov idea as a practical check: the child must not require stricter inputs, weaken promised results, or break the parent's invariants. I do not decide only because the names form an is-a sentence or because most parent code will be reused. If I only need formatting, persistence, or another capability, composition normally expresses the relationship more honestly.
When to use inheritance — valid use cases
Direct Answer
Inheritance is appropriate when the child satisfies a stable behavioral subtype contract and the parent is intentionally designed for extension. Useful cases include a small abstract base with documented template hooks or a framework base class meant to be subclassed. A real-world 'is-a' sentence, percentage of reused code, or fixed hierarchy depth is not enough by itself.
Code Example
abstract class Shape {
abstract double area();
String describe() {
return "area=" + area();
}
}
final class Circle extends Shape {
private final double radius;
Circle(double radius) {
if (radius < 0) throw new IllegalArgumentException("radius");
this.radius = radius;
}
@Override double area() {
return Math.PI * radius * radius;
}
}
void printArea(Shape shape) {
System.out.println(shape.describe());
}
printArea(new Circle(2));
This inheritance is useful because callers need the Shape contract and Circle preserves its rules. The class names alone do not prove the design; the contract does.
Common Mistakes & Pitfalls
- Using taxonomic is-a as proof: behavioral substitution is the stronger test.
- Quoting a fixed safe hierarchy depth: complexity depends on contracts and change rate, not a universal number.
- Extending a class only for helper methods: that creates a misleading subtype.
- Subclassing a class not designed for it: undocumented self-calls and protected state can be fragile.
- Rejecting every inheritance use: stable abstract bases and framework extension points can be appropriate.
Check your understanding
Answer these without looking back at the article.
- What is the Template Method pattern?
- How do you decide between inheritance and composition for a new class?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.