Java 8: Default Method Resolution Rules
With the introduction of default methods in Java 8, it is now possible for a class to inherit the same method from multiple places (such as another class or interface). The following rules can be used to determine which method is selected in such cases:
- A class or superclass method declaration always takes priority over a default method
- Otherwise, the method with the most specific default-providing interface is used
- Finally, if the methods are equally specific, there will be a compiler error and you will be forced to explicitly override the method and specify which one your class should call
Let’s look at a few examples and apply these rules.
Example 1:
What does the following code print?
public interface A { default void name() { System.out.println("A"); } } public interface B { default void name() { System.out.println("B"); } } public class C implements A { @Override public void name() { System.out.println("C"); } } public class D extends C implements A, B { public static void main(final String... args) { new D().name(); } }
Answer: C
This is because, as stated in Rule 1, the method declaration of name()
from the superclass C
takes priority over the default methods declarations in A
and B
.
Example 2:
What does the following code print?
public interface A { default void name() { System.out.println("A"); } } public interface B extends A { @Override default void name() { System.out.println("B"); } } public class C implements A {} public class D extends C implements A, B { public static void main(final String... args) { new D().name(); } }
Answer: B
Unlike the previous example, C
does not override name()
, but since it implements A
, it has a default method from A
. According to Rule 2, if there are no methods in the class or superclass, the most specific default-providing interface is selected. Since B
extends A
, it is more specific and, as a result, “B” is printed.
Example 3:
What does the following code print?
public interface A { default void name() { System.out.println("A"); } } public interface B { default void name() { System.out.println("B"); } } public class D implements A, B { public static void main(final String... args) { new D().name(); } }
Answer: Compiler error! Duplicate default methods named name with the parameters () and () are inherited from the types B and A
In this example, there’s no more-specific default-providing interface to select, so the compiler throws an error. To resolve the error, you need to explicitly override the method in D
and specify which method declaration you want D
to use. For example, if you want to use B
‘s:
class D implements A, B { @Override public void name() { B.super.name(); } }
Example 4:
What does the following code print?
public interface A { default void name() { System.out.println("A"); } } public interface B extends A {} public interface C extends A {} public class D implements B, C { public static void main(final String... args) { new D().name(); } }
Answer: A
The sub-interfaces B
and C
haven’t overridden the method, so there is actually only the method from A
to choose from. As a side note, if either B
or C
(but not both) had overridden the method, then Rule 2 would have applied. By the way, this is the diamond problem.
Reference: | Java 8: Default Method Resolution Rules from our JCG partner Fahd Shariff at the fahd.blog blog. |
I understand the purpose of default method in interface. It will not break the contract if somebody already has implementation using this contract. So there is no contract violation if he doesn’t want to implement default method. But isn’t violating S.O.L.I.D – ISP?