Because inheritance is possible from multiple interfaces, the same default method can be inherited from different paths. Since each inherited default method provides a different implementation, the compiler needs a way of selecting the declaration to use. This is its method:
- Classes always win. A declaration in the class or a superclass takes priority over any default method declaration.
- Otherwise, the method with the same signature in the most specific default-providing interface is selected. For example, based on the rules above the following code will print
Hello World from B
:public interface A { default void hello() { System.out.println("Hello World from A"); } } public interface B extends A { default void hello() { System.out.println("Hello World from B"); } } public class C implements B, A { public static void main(String... args) { new C().hello(); } }
Conflicts are not always avoidable. If, in the example above, interface B
was declared without extending A
, then C
would inherit default methods with matching signatures from unrelated interfaces. Compiling that code would produce the error messages:
class C inherits unrelated defaults for hello() from types A and B
reference to hello is ambiguous, both method hello() in A and method hello() in B match.
Note that the first error would be reported whether or not there was a call to the inherited default method. The conflict must be resolved by overriding. If desired, one of the inherited methods can be selected using the new syntax X.super.m(...)
where X
is the superinterface and m
the method to select:
public class C implements B, A {
public void hello() {
A.super.hello();
}
...
}
This now prints Hello World from A
. Note that this syntax can only be used to resolve a conflict, not to override either of the two principal rules listed above.
Leave a Reply