Skip to main content

Section 8.1 Why Inheritance?

Inheritance is a fundamental mechanism in object-oriented programming where one class (the subclass) acquires the properties and behaviors of another class (the superclass). This establishes an "is-a" relationship, where the subclass represents a specialized version of the superclass. For example, a SavingsAccount is a specialized type of BankAccount.
Consider this concrete example of inheritance in action:
// The superclass containing shared functionality
public class BankAccount {
    protected double balance;
    
    public void deposit(double amount) {
        if (amount >= 0) {
            balance += amount;
        }
    }
    
    public void withdraw(double amount) {
        if (amount >= 0 && amount <= balance) {
            balance -= amount;
        }
    }
}

// The subclass inherits and extends functionality
public class SavingsAccount extends BankAccount {
    private double interestRate;
    
    public void applyInterest() {
        balance += balance * interestRate;
    }
}
This example demonstrates how inheritance reduces code duplication: SavingsAccount automatically gains the deposit and withdraw methods without rewriting them. Yet it also extends this functionality with its own applyInterest method that’s specific to savings accounts.
While inheritance powerfully enables code reuse, it creates stronger coupling between classes than other reuse mechanisms. This means changes to the superclass can potentially affect all subclasses, sometimes in unexpected ways. Effective use of inheritance requires careful consideration of these relationships.
Object-oriented programming offers several code reuse mechanisms, each serving different purposes:
  • Methods: Prefer simple methods when the shared functionality is a behavior that doesn’t require shared state. Example: Use a utility method to calculate distance between two points, which can be called from any class.
  • Interfaces: Use when you need to define a contract that multiple unrelated classes should implement. Example: A Movable interface could be implemented by both Player and Vehicle classes, allowing them to share movement-related method contracts.
  • Composition: Choose when an object uses or contains another object but isn’t a specialization of it. Example: A Game class containing Player, Level, and Enemy objects.
  • Inheritance: Apply only when there’s a clear "is-a" relationship and tight coupling between parent and child is acceptable. Example: A SavingsAccount class extending a base BankAccount class.
As a general guideline, favor composition as your default approach for code reuse. Composition creates more flexible, adaptable designs by reducing coupling between classes. Reserve inheritance for clear "is-a" relationships where shared behavior genuinely represents a specialization hierarchy.
You have attempted of activities on this page.