HuntExams Academy logo
JavaAdvanced#design-patterns#oop

What is the difference between composition and inheritance, and why is 'favor composition over inheritance' recommended?

Answer

Inheritance creates tight is-a coupling to a parent class and can break encapsulation across hierarchy changes. Composition builds has-a relationships by combining objects, offering more flexibility, easier testing, and avoiding fragile base class problems.

Example

// Inheritance (tight coupling)
class Car extends Engine {}
// Composition (flexible)
class Car { private Engine engine; Car(Engine engine) { this.engine = engine; } }

Detailed explanation

Inheritance and composition are two ways to reuse behaviour and structure Java classes. Inheritance uses extends to create a subtype: a child inherits accessible behaviour from its parent and may override methods. It should express a genuine is-a relationship, where the child can satisfy the parent's contract wherever the parent is expected. Composition builds an object from collaborating objects, typically stored in fields, and expresses a has-a relationship. The containing object delegates relevant work to those collaborators instead of inheriting their implementation.

In the example, class Car extends Engine is misleading because a car is not a kind of engine. It also makes Engine's accessible API part of Car's inherited API, potentially exposing operations that do not belong on a car. With class Car { private final Engine engine; Car(Engine engine) { this.engine = engine; } }, Car controls which operations it exposes and when it calls Engine. If Engine is an interface, different implementations can be supplied without changing Car, provided they honour the interface's contract.

Inheritance creates coupling to superclass contracts and can also create dependence on implementation details. Java's dynamic dispatch means a superclass method can call a method overridden by a subclass. A later superclass change that introduces or rearranges such calls may unexpectedly change subclass behaviour, even when the code still compiles. This is one form of the fragile base class problem. Private superclass fields remain private, but protected state and assumptions about internal call sequences can weaken the encapsulation boundary between parent and child.

Composition is generally preferred because dependencies and delegation are explicit, implementations can be selected independently, and tests can inject fakes or stubs rather than construct an entire inheritance hierarchy. It also avoids Java's restriction that a class can extend only one class when assembling multiple behaviours. However, composition may require forwarding methods and does not remove coupling to collaborator contracts. Inheritance remains appropriate for stable, deliberately designed hierarchies whose subtypes preserve behavioural expectations, following the Liskov Substitution Principle. Interviewers look for this balanced judgment: prefer composition for implementation reuse, but use inheritance when substitutability is meaningful and the extension contract is clear.

Key points to remember

  • Inheritance models is-a relationships; composition models has-a relationships through collaborating objects.
  • A valid subtype must preserve its parent's behavioural contract, not merely reuse its code.
  • Superclass implementation changes can unexpectedly affect subclasses through overridden methods and protected state.
  • Composition supports independent implementation selection, explicit dependencies, and simpler test substitution.
  • Favor composition is a design guideline, not a ban on well-designed inheritance.

Common mistakes candidates make

  • Using inheritance solely for code reuse, such as declaring Car extends Engine.
  • Claiming inheritance directly exposes private fields or that composition eliminates all coupling.
  • Saying composition is always better without considering substitutability, forwarding overhead, or intentional extension points.

Likely follow-up questions

How does composition differ from dependency injection?

Composition describes an object containing and using collaborators. Dependency injection describes how those collaborators are supplied, such as passing an Engine through Car's constructor instead of creating it internally.

Can composition and inheritance be used together?

Yes: a class can implement an interface while delegating its work to another object. A decorator, for example, implements the same interface as its wrapped collaborator and adds behaviour around delegated calls.

When should you choose inheritance?

Choose inheritance when the subclass is genuinely substitutable for the parent and the parent explicitly supports extension. Check that overrides preserve expected inputs, outputs, invariants, and error behaviour rather than merely sharing method names.

Interview tip: Use the Car–Engine example, explain the fragile base class problem, and finish with when inheritance is still appropriate.

Related Interview Questions

1
JavaAdvanced#design-patterns

What is the Template Method pattern?

Open
2
JavaBeginner#jdbc

What is JDBC and what are its main components?

Open
3
JavaBeginner#jdbc

What is the difference between Statement and PreparedStatement?

Open