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.