Multiple Inheritance Programs in Java
A component of the object-oriented notion known as multiple inheritances allows a class to inherit properties from multiple parent classes. When methods that have the same signature are present in both superclasses and subclasses, an issue arises. The method's caller cannot specify to the compiler which class method should be called or even which class method should be given precedence.
NOTE: Multiple Inheritances is not supported by Java.
Example 1:
import java.io.*;
class Parent1 {
void fun() {
System.out.println("Parent1");
}
}
class Parent2 {
void fun() {
System.out.println("Parent2");
}
}
class Test extends Parent1,Parent2 {
public static void main(String args[]) {
Test t = new Test();
t.fun();
}
}
Output
C:\javap>java Demo.java
Demo.java:12: error: '{' expected
class Test extends Parent1,Parent2 {
^
1 error
Conclusion: As shown in the code above, issues can arise when utilizing the Test object to call the fun() function, such as deciding whether to use Parent1's or Parent2's fun() method.
Example 2:
import java.io.*;
class GrandParent {
void fun() {
System.out.println("Grandparent");
}
}
class Parent1 extends GrandParent {
void fun() {
System.out.println("Parent1");
}
}
class Parent2 extends GrandParent {
void fun() {
System.out.println("Parent2");
}
}
class Test extends Parent1, Parent2 {
public static void main(String args[]) {
Test t = new Test();
t.fun();
}
}
Output
C:\javap>javac Demo.java
Demo.java:17: error: '{' expected
class Test extends Parent1, Parent2 {
^
1 error
The fun() method throws a compiler error once more because multiple inheritances, which are permitted in other languages like C++, lead to a diamond problem. The code reveals the following: Problems arise when the method fun() is called using the Test object, such as when deciding whether to call the fun() method of Parent1 or Parent2. Java consequently does not allow multiple class inheritances in order to prevent these issues.
Java classes do not enable multiple inheritances, and managing the complexity brought on by multiple inheritances is exceedingly difficult. It causes issues with a number of processes, such as casting and function Object() { [native code] } chaining, and the main reason is that multiple inheritancesare rarely necessary; therefore, it is preferable to do without it to make things clear-cut and simple.
How do Default Methods & Interfaces Solve the Aforementioned Issues?
Java 8 allows interfaces to give a default implementation of methods, and Java 8 supports this. Additionally, a class may support two or more interfaces. If the default methods in both implemented interfaces have the same method signature, the implementing class must either use the super keyword to explicitly specify which default method is to be used in a method other than main(), override the default method in the implementing class, or specify which standard method is to be used in the default overridden method of the effective implementation class.
Example 3:
interface P1{
default void show()
{
System.out.println("Default P1");
}
}
interface P2 {
default void show()
{
System.out.println("Default P2");
}
}
class TestClass implements P1, P2 {
public void show()
{
P1.super.show();
P2.super.show();
}
public void showOfP1() {
P1.super.show();
}
public void showOfP2() {
P2.super.show();
}
public static void main(String args[])
{
TestClass d = new TestClass();
d.show();
System.out.println("Now Executing showOfP1() showOfP2()");
d.showOfP1();
d.showOfP2();
}
}
Output
interface P1{
default void show()
{
System.out.println("Default P1");
}
}
interface P2 {
default void show()
{
System.out.println("Default P2");
}
}
class TestClass implements P1, P2 {
public void show()
{
P1.super.show();
P2.super.show();
}
public void showOfP1() {
P1.super.show();
}
public void showOfP2() {
P2.super.show();
}
public static void main(String args[])
{
TestClass d = new TestClass();
d.show();
System.out.println("Now Executing showOfP1() showOfP2()");
d.showOfP1();
d.showOfP2();
}
}
NOTE: There is a compiler issue if the default method implementation is removed from "TestClass". There won't be a problem if none of the intermediary interfaces implement the root interface if there is a diamond through an interface. If they offer implementation, it can be obtained via the super keyword as described above.
Example 4:
interface GP1 {
default void show()
{
System.out.println("Default GP1");
}
}
interface P1 extends GP1 {
}
interface P2 extends GP1{
}
class TestClass implements P1, P2 {
public static void main(String args[])
{
TestClass d = new TestClass();
d.show();
}
}
Output
Default Gp1
Example 5:
interface Backend {
public void connectServer();
}
class Frontend {
public void responsive(String str) {
System.out.println(str + " is utilized as a front-end language.");
}
}
class Language extends Frontend implements Backend {
String language = "Java";
public void connectServer() {
System.out.println(language + " is utilized as the backend language.");
}
public static void main(String[] args) {
Language java = new Language();
java.connectServer();
java.responsive(java.language);
}
}
Output
java is utilized as the backend language.
Java is utilized as a front-end language.