Inheritance & Polymorphism

Class inheritance and method overriding

Inheritance Fundamentals

Inheritance allows a class to inherit properties and methods from another class, promoting code reusability and establishing “is-a” relationships.

Parent Class

Base class that provides common features

Child Class

Derived class that inherits and extends

extends Keyword

Establishes inheritance relationship

Basic Inheritance Example

Animal - Dog Example

// Parent Class
class Animal {
    protected String name;
    protected int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println(name + " is eating");
    }

    public void sleep() {
        System.out.println(name + " is sleeping");
    }
}

// Child Class
class Dog extends Animal {
    private String breed;

    public Dog(String name, int age, String breed) {
        super(name, age); // Call parent constructor
        this.breed = breed;
    }

    public void bark() {
        System.out.println(name + " is barking");
    }
}

Types of Inheritance

Single Inheritance

One child class inherits from one parent class

    Animal
        |
      Dog

Multilevel Inheritance

Chain of inheritance across multiple levels

    Animal
        |
      Dog
        |
    Bulldog

Hierarchical Inheritance

Multiple child classes inherit from one parent

    Animal
      /   \
    Dog   Cat

Multilevel Inheritance Example

Three-Level Hierarchy

class Vehicle {
    protected String brand;

    public void start() {
        System.out.println("Vehicle started");
    }
}

class Car extends Vehicle {
    protected int doors;

    public void drive() {
        System.out.println("Car is driving");
    }
}

class SportsCar extends Car {
    private boolean turbo;

    public void activateTurbo() {
        System.out.println("Turbo activated!");
    }
}

Important Note

Multiple Inheritance: Java doesn’t support multiple class inheritance but supports multiple interface inheritance.

Polymorphism Concepts

Polymorphism allows objects of different types to be treated as objects of a common base type. “One interface, multiple implementations.”

Compile-time Polymorphism

Method Overloading

Same method name, different parameters

Runtime Polymorphism

Method Overriding

Child class provides specific implementation

Runtime Polymorphism Example

Dynamic Method Dispatch

class Shape {
    public void draw() {
        System.out.println("Drawing a shape");
    }

    public double area() {
        return 0;
    }
}

class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

class Rectangle extends Shape {
    private double length, width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    public void draw() {
        System.out.println("Drawing a rectangle");
    }

    @Override
    public double area() {
        return length * width;
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        Shape[] shapes = {
            new Circle(5),
            new Rectangle(4, 6)
        };

        for (Shape shape : shapes) {
            shape.draw();        // Calls appropriate method
            System.out.println("Area: " + shape.area());
        }
    }
}

Polymorphism Benefits

  • Flexibility: Add new types without changing existing code
  • Maintainability: Single interface for multiple implementations
  • Extensibility: Easy to extend functionality
  • Abstraction: Hide implementation details

Method Overriding

Method overriding allows a child class to provide a specific implementation of a method already defined in its parent class.

Overriding Rules & Example

Complete Override Example

class Employee {
    protected String name;
    protected double baseSalary;

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

    public double calculateSalary() {
        return baseSalary;
    }

    public void displayInfo() {
        System.out.println("Employee: " + name);
    }
}

class Manager extends Employee {
    private double bonus;

    public Manager(String name, double baseSalary, double bonus) {
        super(name, baseSalary);
        this.bonus = bonus;
    }

    @Override
    public double calculateSalary() {
        return baseSalary + bonus; // Enhanced calculation
    }

    @Override
    public void displayInfo() {
        super.displayInfo(); // Call parent method
        System.out.println("Role: Manager");
    }
}
RuleDescriptionExample
Same Method SignatureName, parameters must match exactlypublic void draw()
Access ModifierCan’t reduce visibilityprotected -> public (OK)
Return TypeSame or covariant return typeObject -> String (OK)
@Override AnnotationOptional but recommendedCompile-time checking

Method Overloading

Method overloading allows multiple methods with the same name but different parameters in the same class.

Overloading Examples

Calculator with Overloaded Methods

class Calculator {

    // Different number of parameters
    public int add(int a, int b) {
        return a + b;
    }

    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // Different parameter types
    public double add(double a, double b) {
        return a + b;
    }

    // Different parameter order
    public String add(String str, int num) {
        return str + num;
    }

    public String add(int num, String str) {
        return num + str;
    }
}

// Usage
Calculator calc = new Calculator();
System.out.println(calc.add(5, 3));           // 8
System.out.println(calc.add(5, 3, 2));        // 10
System.out.println(calc.add(5.5, 3.2));       // 8.7
System.out.println(calc.add("Result: ", 42)); // Result: 42

Method Overloading

  • Same class
  • Same method name
  • Different parameters
  • Compile-time polymorphism
  • Static binding

Method Overriding

  • Parent-child classes
  • Same method signature
  • Different implementation
  • Runtime polymorphism
  • Dynamic binding

Best Practices

Access Modifiers

  • Use protected for inheritance
  • Keep fields private when possible
  • Provide public methods for access

Method Design

  • Always use @Override annotation
  • Call super() in constructors
  • Keep method names descriptive

Class Design

  • Follow “is-a” relationship rule
  • Prefer composition over inheritance
  • Keep inheritance hierarchies shallow

Common Pitfalls to Avoid

Watch Out For

  • Deep Inheritance: Avoid more than 3-4 levels
  • Overriding private methods: Not possible, creates new method
  • Constructor chaining: Always call super() explicitly
  • Method hiding: Static methods are hidden, not overridden

Quick Reference

Inheritance Keywords

  • extends - Inherit from class
  • super - Access parent members
  • this - Current object reference
  • @Override - Override annotation

Access Levels

  • private - Same class only
  • protected - Package + subclasses
  • public - Everywhere
  • default - Package only

Remember

Inheritance models “is-a” relationships - A Dog IS-A Animal

Polymorphism provides flexibility - One interface, many implementations