Multiple Inheritance Ambiguity with Interface
Solution 1
The diamond problem only applies to implementation inheritance (extends
in all versions of Java prior to Java 8). It doesn't apply to API inheritance (implements
in all versions of Java prior to Java 8).
Since interface methods with matching type signatures are compatible, there is no diamond problem if you inherit the same method signature twice: matching method signatures simply coalesce instead. (And if the type signatures aren't the same, then you don't have the diamond problem either.)
In Java 7 and below, the only way to inherit implementation code was via the extends
keyword, which restricts to at most one parent. Therefore there is no multiple implementation inheritance and the diamond problem does not exist.
Java 8 adds a new wrinkle because it allows interfaces to have implementation code. It still escapes the diamond problem by simply falling back to the previous behavior (no implementation inheritance) when you're implementing multiple interfaces with methods that have matching signatures.
Solution 2
To add to existing answers about Java8 multiple inheritance with interfaces (a.k.a. how Java still avoids the diamond problem):
There are three rules to follow:
A class always wins. Class's own method implementation takes priority over default methods in Interfaces.
If class doesn't have any: the most specific interface wins
- If above is not the case, inheriting class has to explicitly state which method implementation it's using (otherwise it won't compile)
Solution 3
Java overcomes this problem even though interfaces can have default implementations of methods, because the default implementation is either unambiguous (the one in class A
) or the situation is solved by some rule (when class B
or class C
overrides the implementation from class A
, see below).
When the supertypes of a class or interface provide multiple default methods with the same signature:
- Instance methods are preferred over interface default methods.
- Methods that are already overridden by other candidates are ignored. This circumstance can arise when supertypes share a common ancestor.
However, if two or more independently defined default methods conflict, or a default method conflicts with an abstract method, then the Java compiler produces a compiler error. You must explicitly override the supertype methods. In this case you could invoke any of the of the default implementations with the super keyword.
Solution 4
Java doesn't support multiple inheritance, so the diamond problem doesn't arise. If B & C are interfaces, then there is no implementation in the interfaces. Even if B & C override the method in interface A (cannot be a class), the methods will have same signature. There is no ambiguity regarding which implementation to use, because there is no implementation.
Solution 5
With default methods in interface introduced in Java 8, multiple inheritance related problem may arise, there are 3 scenarios -
1- If implementing class overrides the default method and provides its own functionality for the default method then the method of the class takes priority over the interface default methods.
2-When class implements both interfaces and both have the same default method, also the class is not overriding that method then the error will be thrown.
3-In case when an interface extends another interface and both have the same default method, the inheriting interface default method will take precedence.
read more about it here.
Razib
Updated on June 07, 2022Comments
-
Razib almost 2 years
We all know about the diamond problem regarding multiple inheritance -
A / \ B C \ / D
This problem describe an ambiguous situation for class
D
. If classA
has a method and both/either ofB
and/orC
override the method then which version of method doesD
override?Is this problem also applicable for interfaces in Java? If not, how do Java interfaces overcome this problem?
-
vinay about 9 yearsAs Daniel Pryden said things get a little tricky with Java 8.
-
supercat about 9 yearsI don't think Java 8 really escapes the diamond problem. If B:A, C:A, D:B and D:C, and B contains a default implementation for one of A's methods and C doesn't, then that implementation may be used in D, but from what I understand it would then be a breaking change for C to add a default implementation of that method.
-
Daniel Pryden about 9 years@supercat: Good point. Depending on your point of view, you could say that Java 8 does have the diamond problem, but just makes the complex cases compile-time errors so that the behavior is easier to reason about (compared with, say, C++).
-
supercat about 9 yearsI don't think they're necessarily compile-time errors, since C's default implementation could have been added between the time code using D was compiled and the time the code is run. I don't remember what Java does in that case but for the scenario an implementation of D is compiled, A adds a member, a consumer of D which uses the new member is compiled, and then B is compiled with a default implementation. At that point, D's implementation and consumer will work. If C is compiled with a default implementation, though, I don't see any good course of action for the JVM.
-
Andreas over 7 years@supercat FYI: JVM will throw
IncompatibleClassChangeError: Conflicting default methods
if B and C both have default implementation, and D didn't override. It's both a compile error and a runtime error. -
supercat over 7 years@Andreas: I wonder how often it's necessary to add default implementations to a method which is declared in a parent interface? If default implementations could only be added to the interface wherein a method is declared, that would avoid deadly-diamond issues. On the flip side, it would be helpful to be able to specify multiple default-method overloads for an interface method and have Java bind to the first one which would be satisfied by an implementing class or, going further, allow an interface to specify that any class which can satisfy overloads for all its methods should be...
-
supercat over 7 years...regarded as implementing it. This would make it possible to e.g. define an interface StringishThing which could be "implemented" by String or by other user classes, and offered some useful core methods that are missing from CharSequence.
-
ashish pandey over 4 yearsNo implementation in the interfaces is valid till Java 7 from Java 8 even interface can have a concrete method.
-
Dmytro Melnychuk over 2 yearsActually, first and third points describe that class implementation takes priority