Java OOPs Simplified - Part 3

Java OOPs Simplified - Part 3

In this article, I will explain the concept of Multiple Inheritance and Hybrid Inheritance along with it's examples in simple words.

Multiple Inheritance

Java does not support multiple inheritance of classes, where a class inherits from more than one class. However, it supports multiple inheritance through interfaces.

Attempting to inherit a child class from two parent classes is not allowed in Java due to potential ambiguity for the compiler.

class Class1 {
    void display(){
        System.out.println("Hello");
}
}

class Class2 {
    void display(){
       System.out.println("Hi");
}
}

// This would result in a compilation error because it tries to inherit from both Class1 and Class2.
class MyClass extends Class1, Class2 {
    // MyClass code
}

For instance, consider two parent classes, Parent Class 1 and Parent Class 2, both containing a method named "void display()."

When you call this method on an object of the child class, the compiler faces a difficult situation in determining which version of "void display()" to execute, leading to confusion and, therefore, Java prohibits inheriting from multiple parent classes simultaneously.

So how can we solve this issue? That's where Interface comes into play. Using interfaces we can easily resolve this issue.

So the next question is why there is no ambiguity for the compiler when we use Interfaces instead of Classes?

The answer to this is straightforward: in interfaces, all methods are abstract by default, meaning they are declared without any method body. To illustrate this concept, let me provide you with an example to clear all confusion.

// Define two interfaces
interface Interface1 {
    void display();
}

interface Interface2 {
    void display();
}

// Implement the interfaces in a class
class MyClass implements Interface1, Interface2 {
    @Override
    public void display() {
        System.out.println("Hello");
    }
}

public class Main {
    public static void main(String[] args) {
        // Create an object of the class
        MyClass myObj = new MyClass();

        // Call methods from the implemented interfaces
        myObj.display();
    }
}

In this example:

  1. We define two interfaces, Interface1 and Interface 2, each with a single abstract method.

  2. We create a class MyClass that implements both Interface1 and Interface2.

  3. Inside MyClass, we provide implementations for the methods defined in both interfaces. Here since both methods are the same, we only need to implement the method once.

  4. In the Main class, we create an object of MyClass and call the methods from both interfaces.

This demonstrates that a class can implement multiple interfaces in Java. Thus there won't be any ambiguity for the compiler here.

NB: If the parent classes have methods with different names, then you would need to provide the method implementations for both methods inside MyClass, just as we did for the method void display().

NB: Interface is also a user-defined data type in Java similar to that of class.

Now let's move on to the Hybrid Inheritance.

Hybrid Inheritance

It refers to the combination of different types of inheritance within a program.

It involves multiple inheritance, along with some other type of inheritance such as single inheritance or multilevel inheritance.

But Java doesn't directly support this kind of inheritance as it uses multiple inheritance and this will lead to one of the potential complications called "diamond problem".

(The diamond problem refers to a situation where a class inherits from 2 parent classes with a common ancestor)

In Java, we can achieve this form of inheritance by combining a single inheritance of classes and multiple inheritance through interfaces. This will resolve code complexity and ambiguity issues.

Let's look at an example, of how we solve the diamond problem in inheritance using interfaces.

// Define a grandparent interface
interface Grandparent {
    void grandparentMethod();
}

// Define two parent interfaces
interface Parent1 {
    void parent1Method();
}

interface Parent2 {
    void parent2Method();
}

// Implement the grandparent and parent interfaces in a class
class MyClass implements Grandparent, Parent1, Parent2 {
    @Override
    public void grandparentMethod() {
        System.out.println("Grandparent method implementation");
    }

    @Override
    public void parent1Method() {
        System.out.println("Parent 1 method implementation");
    }

    @Override
    public void parent2Method() {
        System.out.println("Parent 2 method implementation");
    }

    void childMethod() {
        System.out.println("Child method implementation");
    }
}

public class Main {
    public static void main(String[] args) {
        // Create an object of MyClass
        MyClass myObj = new MyClass();

        // Call methods from all interfaces
        myObj.grandparentMethod();
        myObj.parent1Method();
        myObj.parent2Method();
        myObj.childMethod();
    }
}

In the above code,

  1. We define a Grandparent interface with one method, grandparentMethod.

  2. We define two parent interfaces, Parent1 and Parent2, each with one method.

  3. The MyClass class implements all three interfaces, providing implementations for all methods.

  4. Additionally, we define a childMethod specific to the MyClass class.

While this example does not directly demonstrate hybrid inheritance with multiple classes, it does show a scenario with one grandparent interface and two parent interfaces, which provides a similar structural concept to what you might see in hybrid inheritance situations.