Inheritance and Polymorphism

Dive deeper into inheritance, its benefits, and different types (single, multiple, multilevel). Understand polymorphism (method overriding and overloading) and its applications.


Multilevel Inheritance in Java

Explanation of Multilevel Inheritance

Multilevel inheritance in Java is a type of inheritance where a class inherits from a derived class, thus forming a chain of inheritance. In other words, a class serves as a base class for another derived class, which in turn serves as a base class for another derived class. This creates a hierarchy where a class inherits properties and behaviors from its immediate parent class, which in turn inherits from its parent class, and so on.

Key characteristics of multilevel inheritance:

  • Chain of Inheritance: Classes inherit properties and methods from their immediate parent and transitively from all ancestor classes.
  • Code Reusability: It promotes code reusability as derived classes inherit code from parent classes.
  • Hierarchy: It establishes a clear hierarchical relationship between classes.
  • Transitive Nature: If class C inherits from class B, and class B inherits from class A, then class C implicitly inherits from class A as well.

Multilevel inheritance is useful for representing complex relationships between objects where one object is a specialized version of another, and that object, in turn, is a specialized version of an even more general object.

Implementation and Code Example

Grandparent Class

Let's define a grandparent class called Animal.

 public class Animal {
    String name;

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

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

Parent Class

Now, let's create a parent class called Mammal that inherits from the Animal class.

 public class Mammal extends Animal {
    String furColor;

    public Mammal(String name, String furColor) {
        super(name); // Call the constructor of the Animal class
        this.furColor = furColor;
    }

    public void giveBirth() {
        System.out.println(name + " is giving birth to live young.");
    }
} 

Child Class

Finally, let's define a child class called Dog that inherits from the Mammal class.

 public class Dog extends Mammal {
    String breed;

    public Dog(String name, String furColor, String breed) {
        super(name, furColor); // Call the constructor of the Mammal class
        this.breed = breed;
    }

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

    public static void main(String[] args) {
        Dog myDog = new Dog("Buddy", "Brown", "Golden Retriever");

        // Accessing methods from all parent classes:
        myDog.eat();        // Inherited from Animal
        myDog.giveBirth();  // Inherited from Mammal
        myDog.bark();       // Defined in Dog
    }
} 

Explanation of the Code

In this example:

  • The Animal class is the grandparent class, representing a general animal. It has the property name and the method eat().
  • The Mammal class inherits from the Animal class, adding the property furColor and the method giveBirth(). It also calls the Animal class's constructor using super(name) to initialize the inherited name property.
  • The Dog class inherits from the Mammal class, adding the property breed and the method bark(). It also calls the Mammal class's constructor using super(name, furColor).

In the main method of the Dog class, we create an instance of the Dog class and demonstrate that it can access methods from all its parent classes (Animal and Mammal) as well as its own methods.

When you run this code, the output will be:

 Buddy is eating.
Buddy is giving birth to live young.
Buddy (a Golden Retriever) is barking.