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.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.