What is the difference between composition and inheritance, and when would you prefer composition?
Inheritance is an "is-a" relationship where a class extends another and reuses its code. Composition is a "has-a" relationship where a class holds other objects and delegates work to them. Prefer composition by default because it keeps classes loosely coupled and lets you swap behaviour, and use inheritance only for a true, stable "is-a" relationship.
Explain it simply
A smartphone has a camera, a battery and a SIM slot. It is not a camera. If a better camera comes out, the manufacturer swaps the module and the phone still works. That is composition: build something by putting parts together.
A Royal Enfield Classic is a motorcycle. It automatically gets everything a motorcycle has: wheels, an engine, brakes. That is inheritance. It works well when the relationship is real and does not change. It goes wrong when you force it, like saying a phone "is a" camera just to reuse the click-photo feature.
Example
// Inheritance: tightly tied to the parent
class Vehicle {
String start() { return "Engine started"; }
}
class Car extends Vehicle { }
// Composition: behaviour is a part you plug in
interface Engine { String start(); }
class PetrolEngine implements Engine {
public String start() { return "Petrol engine started"; }
}
class ElectricMotor implements Engine {
public String start() { return "Electric motor humming"; }
}
class Scooter {
private final Engine engine; // Scooter HAS an engine
Scooter(Engine engine) { this.engine = engine; }
String start() { return engine.start(); } // delegate the work
}
public class Garage {
public static void main(String[] args) {
System.out.println(new Car().start()); // prints: Engine started
System.out.println(new Scooter(new PetrolEngine()).start()); // prints: Petrol engine started
System.out.println(new Scooter(new ElectricMotor()).start());// prints: Electric motor humming
}
}The Scooter did not change at all to support an electric motor. With inheritance, you would need a new subclass, and a third variant would need yet another.
How it works
- Inheritance (
extends) copies the parent's public and protected behaviour into the child at compile time. The child depends on the parent's internal details, and a change in the parent can break every child. Java allows only one parent class. - Composition stores another object in a field and forwards calls to it. The outer class depends only on the part's public interface. Parts can be swapped at runtime or replaced with a fake in tests.
Ask one question: "Is the child really a kind of the parent everywhere the parent is used?" If yes, inheritance can fit. If the answer is "it just needs some of that behaviour", use composition.
Real-world use
- A
PaymentServicethat has aPaymentGateway(Razorpay, Paytm, a mock in tests) instead of extending one of them. - Spring and other frameworks inject dependencies through constructors, which is composition.
- Java's own
Stack extends Vectoris often cited as a design mistake: a stack should not exposeadd(index, element), but it inherits it.
Common mistakes
- Using inheritance only to reuse a couple of methods, which ties the classes together for life.
- Building deep hierarchies (
Animal → Mammal → Dog → Labrador → ServiceLabrador). Every level adds coupling. - Thinking composition means never using inheritance. Sharing a contract through an interface and a real "is-a" model, like
Circlebeing aShape, are fine.
What to say in the interview
"Inheritance models an is-a relationship: the child extends the parent and reuses its code, but it's tightly coupled to the parent's implementation and Java allows only one parent. Composition models a has-a relationship: a class holds other objects, usually through an interface, and delegates to them. I prefer composition by default because I can swap parts, like plugging a different payment gateway into a service, and test with mocks. I use inheritance when the is-a relationship is genuine and stable."
Follow-up questions
- What is the "fragile base class" problem?
- How does the Strategy pattern use composition?
- What is the difference between composition and aggregation?
- Why does Java not support multiple inheritance of classes?
Go deeper
Read these once the basics above feel easy.
UML separates two kinds of "has-a". In composition, the part cannot live without the whole: an Order's line items are created and destroyed with the order. In aggregation, the part can exist on its own: a Team has Players, but a player still exists if the team is dissolved. In code both look like a field, so the difference is about ownership and lifecycle. The "fragile base class" problem is the main reason to be cautious with inheritance: if a parent's addAll internally calls add, and a child overrides add to count items, the count can be doubled. The child broke because of a parent detail it could not see.