Skip to main content

1.3 Inheritance & Composition

← Back to Chapter 1: OOPs Concepts

Software architecture relies heavily on structured relationships between components. Java supports two primary modeling mechanisms: Inheritance (IS-A) and Composition (HAS-A).


1. Inheritance (IS-A Relationship)​

Inheritance allows a subclass to acquire fields and methods of a parent superclass using the extends keyword:

public class Employee {
protected final String id;
protected final String name;

public Employee(String id, String name) {
this.id = id;
this.name = name;
}

public double calculatePay() {
return 3000.0;
}
}

public class Manager extends Employee {
private final double bonus;

public Manager(String id, String name, double bonus) {
super(id, name); // 1. Must invoke super constructor first
this.bonus = bonus;
}

@Override
public double calculatePay() {
return super.calculatePay() + bonus; // 2. Delegate to superclass implementation
}
}

Key Inheritance Constraints in Java​

  1. Single Class Inheritance: Java does not support multiple class inheritance (class A extends B, C is illegal) to avoid the "Diamond Problem".
  2. Object Superclass: All Java classes directly or indirectly inherit from java.lang.Object.
  3. final Classes: Classes marked final (like java.lang.String) cannot be extended.

2. Composition (HAS-A Relationship)​

Composition builds complex types by assembling smaller, independent components rather than inheriting behavior:

public class DatabaseConnectionPool {
public void executeQuery(String sql) { /* ... */ }
}

public class UserRepository {
// HAS-A relationship: UserRepository is NOT a ConnectionPool
private final DatabaseConnectionPool pool;

public UserRepository(DatabaseConnectionPool pool) {
this.pool = pool;
}

public void findUser(long id) {
pool.executeQuery("SELECT * FROM users WHERE id = " + id);
}
}

3. "Favor Composition over Inheritance"​

The Gang of Four (GoF) design principle recommends composition over class inheritance:

FactorInheritance (IS-A)Composition (HAS-A)
CouplingTight coupling: Changes to superclass ripple down into subclassesLoose coupling: Components interact purely via interfaces
EncapsulationSuperclass implementation details leak into child classesBlack-box reuse: Internal state remains private
FlexibilityFixed at compile-time (cannot change parent class dynamically)Swappable at runtime via Dependency Injection (Spring IoC)
TestingDifficult to mock deep inheritance hierarchiesEffortless to inject mock dependencies in unit tests