Diamond Problem of Inheritance in Java 8
Upasana | May 05, 2019 | 3 min read | 6,473 views
What is diamond problem of Inheritance?
Diamond Problem of inheritance is an ambiguity that can arise as a consequence of allowing multiple inheritance in language like C++.
Consider the below classes in C++
class A {
void foo() { ... }
}
class B extends A {}
class C extends A {}
class D extends B, C {}
In the code above, the implementation of method foo()
inherited by class D is unambiguously that defined by class A. But as soon as class B and class C starts to provide its own implementation for method foo()
, the ambiguity will arrive in method resolution by Class D. This trap is known as diamond problem of multiple inheritance.
Since Java does not allow multiple inheritance for classes (only multiple interfaces are allowed), so diamond problem can not exist in Java. At any given point in time, a given Java class can extend from only one super class.
How does Java 8 tackles diamond problem of multiple inheritance?
Java 8 brought a major change where interfaces can provide default implementation for its methods. Java designers kept in mind the diamond problem of inheritance while making this big change. There are clearly defined conflict resolution rules while inheriting default methods from interfaces using Java 8.
- Rule 1
-
Any method inherited from a class or a superclass is given higher priority over any default method inherited from an interface.
class has higher precedence than interface default methods.In the diagram above,
foo()
method of class D will inherit from class C. - Rule 2
-
Derived interfaces or sub-interfaces take higher precedence than the interfaces higher-up in the inheritance hierarchy.
In the above class diagram, foo()
of class C will inherit from default method of interface B.
- Rule 3
-
In case Rule 1 and Rule 2 are not able to resolve the conflict then the implementing class has to specifically override and provide a method with the same method definition.
In above class diagram, since interface A & B are at same level, to resolve conflict, class C must provide its own implementation by overriding method foo()
.
class C {
void foo() {
B.super.foo(); (1)
}
}
1 | foo() method can refer to A or B’s default implementation using A.super.foo() or B.super.foo() |
Question: what will be output of the below program?
interface A {
default void foo() { System.out.println("hello from A"); }
}
interface B extends A {
default void foo() { System.out.println("hello from B"); }
}
interface C extends A {}
class D implements B, C {}
C c = new D();
c.foo();
hello from B
The static type of c is unimportant here; what really counts is that it is an instance of class D, whose most specific version of foo()
is inherited from class B.
Top articles in this category:
- Producer Consumer Problem using Blocking Queue in Java
- Java 8 Parallel Stream custom ThreadPool
- What are four principles of OOP, How aggregation is different than Composition?
- How will you increment each element of an Integer array, using parallel operation
- Difference between Implementing Runnable and Extending Thread
- Factorial of a large number in Java BigInteger
- What is Double Checked Locking Problem in Multi-Threading?