The default inheritance of the default Java 8 method

Say the following types exist:

public interface Base { default void sayHi(){ System.out.println("hi from base"); } } public interface Foo extends Base { @Override default void sayHi(){ System.out.println("hi from foo"); } } public interface Bar extends Base { } public class MyClass implements Foo, Bar { public static void main(String[] args) { MyClass c = new MyClass(); c.sayHi(); } } 

In this case, if main is executed, "hello from foo" is printed. Why does the Foo implementation take precedence? Doesn't Bar inherit sayHi() from Base , since if MyClass to implement only Bar , would the Base implementation be implemented? Therefore, it would be wise for the code to still not compile. Also, since Bar must have a Base implementation of sayHi() , why can't I override it in MyClass , for example:

 @Override public void sayHi() { Bar.super.sayHi(); } 

When trying to do this, the following error occurs:

The bad type of the Bar classifier in the default supercall method, sayHi () is overridden in Foo

+6
source share
2 answers

This behavior is set using almost your exact example in JLS 9.4.1 , with only some names changed around:

 interface Top { default String name() { return "unnamed"; } } interface Left extends Top { default String name() { return getClass().getName(); } } interface Right extends Top {} interface Bottom extends Left, Right {} 

Right inherits name () on top, but Bottom inherits name () on the left, not right. This is because name () from Left overrides the declaration of name () at the top.

JLS does not seem to provide the specific concrete reason I see; this is exactly how the Java developers decided on inheritance to work.

+9
source

This is by design. From JLS 12.15.3 :

If the form is a TypeName. super. Identifier [TypeArguments], then:

  • If TypeName is an interface, let T be a type declaration that directly includes a method call. A compile-time error occurs if there is a method other than a compile-time declaration that overrides ( §9.4.1 ) the compile-time declaration from a direct superclass or direct superinterface T.

In the case when the superinterface overrides the method declared in the grandparent interface, this rule prevents the child interface from “skipping” the redefinition by simply adding grandma to the set of direct superinterfaces. The appropriate way to access the functions of grandparents is the direct superinterface, and only if this interface decides to set the desired behavior. (As an alternative, the developer is free to define his own additional superinterface, which provides the desired behavior when calling the super-method.)

+9
source

All Articles