What is inheritance, and when does an 'is-a' relationship justify using it?
Interview preparation resource from Gate Smashers.
Inheritance is an object-oriented mechanism in which a derived class extends a base class, forming a subtype relationship. It is appropriate when the derived type is genuinely a specialized form of the base type and can be used wherever the base type is expected without violating its contract. This is the practical meaning of an “is-a” relationship and supports polymorphism. Use inheritance to model a stable shared abstraction, not merely to reuse implementation; for “has-a” or “uses-a” relationships, composition is usually a better fit.
// Correct "is-a" example
class Animal {
void eat() {
System.out.println("eating");
}
}
class Bird extends Animal {
void fly() {
System.out.println("flying");
}
}
// Potential LSP violation when Rectangle allows independent dimensions
class Rectangle {
protected int width;
protected int height;
void setWidth(int width) {
this.width = width;
}
void setHeight(int height) {
this.height = height;
}
int area() {
return width * height;
}
}
class Square extends Rectangle {
@Override
void setWidth(int width) {
this.width = width;
this.height = width;
}
@Override
void setHeight(int height) {
this.width = height;
this.height = height;
}
}
// Composition for a "has-a" relationship
class Engine {
void start() {
System.out.println("engine started");
}
}
class Car {
private final Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void start() {
engine.start();
}
}What inheritance means
Inheritance lets a derived class reuse and extend the behavior and accessible members of a base class. It also establishes a type relationship: code written against the base type can work with compatible derived objects.
The exact inheritance rules, such as member visibility, multiple inheritance support, and method-overriding behavior, depend on the programming language.
When “is-a” justifies inheritance
An “is-a” statement is a useful starting point, but it is not sufficient by itself. The derived class must preserve the promises made by the base class so that replacing a base object with a derived object does not break correct client code.
This requirement is commonly expressed by the Liskov Substitution Principle: a subtype should honor the behavioral contract of its supertype.
- Specialization: The derived type represents a more specific kind of the base type, such as a Bird being an Animal.
- Substitutability: A derived object can be passed to code expecting the base type without surprising changes in expected behavior.
- Shared abstraction: The base class defines meaningful common behavior or a common interface that clients need to use polymorphically.
- Stable semantics: The hierarchy reflects the domain model rather than being created only to avoid duplicated code.
When to prefer composition
Prefer composition when one object contains, uses, or delegates work to another object. Composition keeps responsibilities separate and avoids forcing a subtype relationship where none exists.
Inheritance can couple a derived class to assumptions and changes in the base class. If the goal is only implementation reuse, delegation to a contained object is often more flexible.
- Has-a relationship: A Car has an Engine, so the Car should contain an Engine rather than extend it.
- Behavior reuse only: If two classes need the same helper behavior but are not substitutable types, extract that behavior into a separate component.
- Contract mismatch: Avoid inheritance when overriding a base operation would require changing its expected meaning or restricting valid base-class behavior.
A common contract mismatch
A Square may satisfy the everyday “is-a Rectangle” statement, but it can violate a mutable Rectangle contract if Rectangle allows width and height to change independently. Making Square setters update both dimensions can surprise code that expects those dimensions to remain independent.
The issue is not the names alone; it is whether the base-class contract was designed so that Square remains substitutable.
