Inheritance vs Composition

🧭 Inheritance vs Composition in Java — When to Use Which?

💡 Understanding the Difference

Both inheritance and composition are ways to reuse code and model relationships between classes in object-oriented programming — but they are used in different scenarios.


🧩 When to Use Inheritance

  • Use inheritance when there is a clear “IS-A” relationship between two classes.
    Example:

    • An Employee is a Person.

    • A Car is a Vehicle.

  • Inheritance is preferred when a subclass needs to expose or override all behaviors of its parent class.

Key idea: Inheritance allows one class to extend another and automatically gain access to its properties and methods.


🧩 When to Use Composition

  • Use composition when there is a “HAS-A” relationship.
    Example:

    • A Car has a Engine.

    • A Company has Employees.

  • Composition is preferred when a class needs some behaviors or data from another class but does not need to inherit everything.

Key idea: Composition uses an object reference to another class instead of extending it, allowing greater flexibility and less coupling.


🧠 Example 1 — Using Inheritance

public class InheritanceTest { public static void main(String[] args) { Person p = new Employee(); System.out.println(p.getAge()); System.out.println(p.getPersonCountry()); } } class Person { public int getAge() { return 1; } public String getPersonCountry() { return "INDIA"; } } class Employee extends Person { public int getAge() { return 2; } }

🧩 Output

2 INDIA

Here, the Employee class inherits from Person (an IS-A relationship).
So, Employee automatically has access to all methods of Person, including getPersonCountry().


⚠️ Limitation of Inheritance

If you try to change the return type of getAge() in the Employee class from int to String, the compiler will throw an error.

class Employee extends Person { public String getAge() { // ❌ Error: incompatible return type return "2"; } }

That’s because when you use inheritance, method signatures must match exactly, and return types must be compatible with the parent method’s return type.


🧩 Example 2 — Using Composition

In cases where you only need some properties or different implementations, inheritance may not be suitable.
Here’s how composition helps:

public class CompositionTest { public static void main(String[] args) { Employee1 emp = new Employee1(); System.out.println(emp.getAge()); System.out.println(emp.getPersonCountry()); } } class Person1 { public int getAge() { return 1; } public String getPersonCountry() { return "INDIA"; } } class Employee1 { public String getAge() { // ✅ Different return type allowed return "2"; } public String getPersonCountry() { // Using composition to access Person1's behavior Person1 p1 = new Person1(); return p1.getPersonCountry(); } }

🧩 Output

2 INDIA

Here, Employee1 has-a Person1 object inside it and uses it to call getPersonCountry().
This is compositionEmployee1 is not a Person1, but it uses one.


⚙️ Summary — When to Use Which

ScenarioPreferred ApproachRelationship Type
A subclass should inherit all properties and behaviors from a parent classInheritanceIS-A
A class should only use certain behaviors or data from another classCompositionHAS-A
You want to change or customize method signatures (e.g., return type)CompositionHAS-A
You need polymorphic behavior (Person p = new Employee())

No comments:

Post a Comment

Model Context Protocol (MCP) — Complete Guide for Backend Engineers

  Model Context Protocol (MCP) — Complete Guide for Backend Engineers Build Tools, Resources, and AI-Driven Services Using LangChain Moder...

Featured Posts