IT234 Object Oriented Programming With Java

Object Oriented Programming With JavaUnit 412 min read

Inheritance & Method Overriding: Types, Rules & Real-World Use

Unit 4 of Object Oriented Programming With Java covers inheritance (single, multilevel, hierarchical, multiple via interfaces), method overriding (runtime polymorphism), constructor chaining, and Java’s restrictions on multiple inheritance. It explains how to reuse code, enforce design rules, and implement dynamic meth

Core Concepts

1. Inheritance: Code Reusability & Hierarchy

Inheritance allows a subclass (child) to inherit fields and methods from a superclass (parent). Java supports four types:

method3()SubclassSuperclass
Inheritance hierarchy: Subclass inherits method1() and method2() from Superclass, adds method3()

Types of Inheritance in Java:

Type Definition Example
Single One subclass inherits from one superclass. Animal → Dog
Multilevel Chain of inheritance (grandparent → parent → child). Vehicle → Car → SportsCar
Hierarchical Multiple subclasses inherit from one superclass. Shape → Circle, Shape → Rectangle
Multiple Not directly supported (Java prohibits it). Solved via interfaces. Interface A + B → Class C (implements both)

Why Java Bans Multiple Inheritance for Classes?

  • Diamond Problem: Ambiguity when two superclasses define the same method.
    class A { void show() {} }
    class B extends A { void show() {} }  // Error if C extends both A and B
    
  • Solution: Use interfaces (multiple interfaces can be implemented).

2. Constructor Chaining in Inheritance

When a subclass object is created, constructors execute in this order:

  1. Superclass constructor (top to bottom).
  2. Subclass constructor.
Superclass constructorSubclass constructorSubclass constructor
Constructor chaining order: Superclass runs first, then Subclass
class Parent {
    Parent() { System.out.println("Parent constructor"); }
}
class Child extends Parent {
    Child() { System.out.println("Child constructor"); }
}
public class Main {
    public static void main(String[] args) {
        Child c = new Child();
    }
}

Output:

Parent constructor
Child constructor

Trace Table:

Step Action State After Step
1 new Child() called Parent constructor executes
2 Parent constructor finishes Child constructor executes
3 Child constructor finishes Object c fully initialized

3. Method Overriding: Runtime Polymorphism

Overriding occurs when a subclass provides a specific implementation of a method already defined in its superclass. Key rules:

  • Signature must match exactly (same name, parameters, return type).
  • Access modifier cannot be more restrictive (e.g., protected → private is invalid).
  • @Override annotation (optional but recommended) ensures correctness.

Example: Shape Hierarchy

class Shape {
    void draw() { System.out.println("Drawing a shape"); }
}
class Circle extends Shape {
    @Override
    void draw() { System.out.println("Drawing a circle"); }
}

Trace:

startnew Circle(), draw() → Circle.draw() (runtime)Output: 'Drawing a circle'Shape (reference type)Circle (actual object)
Dynamic method dispatch: Runtime resolves Circle.draw() despite Shape reference

Real-World Analogy:

  • Nepal’s NTC (National Transport Commission) defines a Vehicle class with a calculateTax() method.
    • A Car subclass overrides it to apply a different tax formula than Bike.
    • At runtime, NTC’s system calls the correct subclass method based on the vehicle type.

4. final Keyword: Restricting Inheritance

Use Case Syntax Example Purpose
Final Class final class SealedClass Prevents inheritance (e.g., String, Integer).
Final Method final void method() Prevents overriding (e.g., Object.hashCode()).
Final Variable final int MAX_SIZE = 100; Constant value (immutable after initialization).

Why Use final?

  • Security: Prevent tampering (e.g., Math.PI).
  • Performance: Optimizes JVM (no runtime method lookup for final methods).
  • Design: Enforces immutability (e.g., String threadsafety).

5. Dynamic Method Dispatch

Java uses runtime polymorphism to determine which overridden method to call. The JVM resolves the method at runtime based on the object’s actual type (not reference type).

Example: Bank Loans

class Loan {
    void calculateInterest() { System.out.println("Default interest"); }
}
class HomeLoan extends Loan {
    @Override
    void calculateInterest() { System.out.println("5% home loan interest"); }
}
class CarLoan extends Loan {
    @Override
    void calculateInterest() { System.out.println("8% car loan interest"); }
}
public class Main {
    public static void main(String[] args) {
        Loan loan1 = new HomeLoan();
        Loan loan2 = new CarLoan();
        loan1.calculateInterest(); // Output: 5%
        loan2.calculateInterest(); // Output: 8%
    }
}

Trace Table:

Object Reference Actual Object Type Method Called Output
loan1 HomeLoan HomeLoan.calculateInterest() "5% home loan interest"
loan2 CarLoan CarLoan.calculateInterest() "8% car loan interest"

In the Real World

  1. eSewa (Nepal):

    • Uses inheritance for payment methods. The base Payment class defines process(), while subclasses like KhaltiPayment and EbsePayment override it with their own APIs.
    • Dynamic dispatch ensures the correct payment gateway is called at runtime.
  2. Pathao (Ride-Hailing):

    • Hierarchical inheritance: Vehicle (superclass) → Car, Bike, Auto (subclasses).
    • Each subclass overrides calculateFare() to apply different pricing logic (e.g., distance-based for cars, time-based for autos).
  3. Nepal Stock Exchange (NEPSE):

    • Abstract classes model Stock (with abstract calculateDividend()), while BlueChipStock and GrowthStock provide concrete implementations.
    • Interfaces like Tradeable (with buy(), sell()) are implemented by all stock types.

Worked Example: College Ranking System

Problem: Design a system where a College class tracks cname and rank. A University subclass adds totalStudents and overrides showRecord() to include university-specific details.

class College {
    String cname;
    int crank;
    void setCollege(String name, int rank) {
        cname = name; crank = rank;
    }
    void showRecord() {
        System.out.println("College: " + cname + ", Rank: " + crank);
    }
}
class University extends College {
    int totalStudents;
    void setUniversity(String name, int rank, int students) {
        setCollege(name, rank); // Reuses superclass method
        totalStudents = students;
    }
    @Override
    void showRecord() {
        super.showRecord(); // Calls superclass method
        System.out.println("Students: " + totalStudents);
    }
}
public class Main {
    public static void main(String[] args) {
        University triChandra = new University();
        triChandra.setUniversity("Tribhuvan University", 1, 50000);
        triChandra.showRecord();
    }
}

Output:

College: Tribhuvan University, Rank: 1
Students: 50000

State After Each Step:

sequenceDiagram
    participant UC as University
    participant C as College
    UC->>C: setCollege("TU", 1)
    C-->>UC: cname="TU", crank=1
    UC->>UC: totalStudents=50000
    UC->>C: showRecord()
    C-->>UC: "College: TU, Rank: 1"
    UC->>UC: "Students: 50000"

Comparison: Inheritance vs. Interfaces

Feature Inheritance (Class) Interface
Keyword extends implements
Methods Can have concrete + abstract Only abstract (default since Java 8)
Variables Can have instance variables Only public static final (constants)
Multiple Support No (diamond problem) Yes (a class can implement many)
Use Case "Is-a" relationship (e.g., Dog is an Animal) "Can-do" relationship (e.g., Flyable interface)
Animal (Class)Dog (Subclass)Mammal (Interface)Flyable (Interface)
Inheritance vs. interfaces: 'is-a' (extends) vs. 'can-do' (implements)

Example: Multiple Inheritance via Interfaces

interface Flyable { void fly(); }
interface Swimmable { void swim(); }
class Duck implements Flyable, Swimmable {
    public void fly() { System.out.println("Flying"); }
    public void swim() { System.out.println("Swimming"); }
}

Exam Tip

  1. Diagrams > Text: Always draw UML class diagrams for inheritance hierarchies. Label:

    • + for public methods,
    • # for protected,
    • - for private.
    • Use solid arrows (--|>) for inheritance, dashed (..|>) for interfaces.
  2. Constructor Chaining: Expect questions on the order of execution. Memorize:

    • Superclass constructors run before subclass constructors.
    • Use super() to explicitly call a superclass constructor (default if omitted).
  3. Method Overriding Pitfalls:

    • Return type: Covariant return types (e.g., Number → Integer) are allowed in Java 5+.
    • @Override: Always use it to catch errors (e.g., typo in method name).
  4. final Keyword:

    • Class: "Cannot be inherited" (e.g., String).
    • Method: "Cannot be overridden" (e.g., Object.hashCode()).
    • Variable: "Cannot be reassigned" (e.g., final int MAX = 100;).
  5. Dynamic Dispatch:

    • The reference type determines which method is accessible, but the actual object type determines which is called.
    • Example: Shape s = new Circle(); → s.draw() calls Circle.draw().
  6. Common Exam Questions:

    • "Why can’t Java support multiple inheritance for classes?" → Diamond problem.
    • "How does constructor chaining work?" → Trace the order with a diagram.
    • "Differentiate between overloading and overriding."
      Feature Overloading Overriding
      Method Signature Same name, different parameters Same name, same parameters
      Return Type Can vary Must match (covariant allowed)
      Polymorphism Compile-time Runtime

Practice Questions (Self-Check)

  1. Code Trace: Given the following, what is the output?

    class A { A() { System.out.print("A"); } }
    class B extends A { B() { System.out.print("B"); } }
    public class Main { public static void main(String[] args) { new B(); } }
    

    Answer: AB (Constructor chaining: A → B).

  2. Design: Create a Vehicle class with start() and a Car subclass that overrides it to print "Car started with key". Use super to call the parent method.

  3. Short Answer:

    • What is the output of System.out.println(new Circle().toString()) if Circle extends Shape and overrides toString()?
    • Why is String declared as final in Java?

Based on the TU BITM syllabus for Object Oriented Programming With Java (IT234), unit 4.

Discussion

Loading…