0

In the following code if I uncomment I3 and implements I2 and I3 then there is a compilation failure with the following error:

unrelated defaults for m2() from I3 and I2

Which is as fine and expected behavior.

However, when I replace I3 with I, it compiles successfully and I am getting I2 as output.

public class DefaultMethodTest implements I, I2 {
    public static void main(String[] args) {
        DefaultMethodTest obj = new DefaultMethodTest();
        obj.m2();
     }
}
    
interface I {
        default void m2() {
        System.out.println("I1");
    }
}

interface I2 extends I {
        default void m2() {
        System.out.println("I2");
    }
}

//interface I3 extends I {
//
//    default void m2() {
//        System.out.println("I3");
//    }
//}

Now I have couple of questions here :

  • Why there is no compilation failure in second case although both interface have same default method m2?

  • Why I2 got precedence over I ?.

Note: This question is not related to java-8-default-method-inheritance

T-Bag
  • 10,916
  • 3
  • 54
  • 118
  • "*In the following code if I uncomment `I3` then there is a compilation failure..*" I can't reproduce this problem. If I *only* uncomment `I3` then compilation error shouldn't appear since `I3` is not used in `public class DefaultMethodTest implements I, I2 {..}`. Your code example should probably include `I3` in `DefaultMethodTest` like `public class DefaultMethodTest implements I, I2, I3 {..}` or `public class DefaultMethodTest implements I2, I3{..}`. – Pshemo Jun 21 '20 at 14:58
  • BTW `System.out.println("I2");` inside `I3` should probably be `System.out.println("I3");` for clarity. – Pshemo Jun 21 '20 at 15:04
  • @Pshemo Done. thanks – T-Bag Jun 22 '20 at 02:43

1 Answers1

2

As per the default method resolution rules, the default method in the most specific default providing interface will be chosen. In your case, both I and I2 has a default method (each) with the same signature. Hence, it will choose I2 which is your most specific default providing interface.

On the other hand, if you implement I2, I3, there will be conflict that you need to resolve (by implementing m2 in your class).

References:

http://www.lambdafaq.org/how-are-conflicting-method-declarations-resolved/ https://javadevcentral.com/default-method-resolution-rules

Thiyagu
  • 17,362
  • 5
  • 42
  • 79
  • why there is no compilation failure ?? – T-Bag Jun 21 '20 at 14:25
  • Why would it fail compilation when I2 wins over I? – Thiyagu Jun 21 '20 at 14:26
  • I don't have a JLS link handy, but it has to do with the Inheritance between `I` and the child classes, which is lost when you inherit two hierarchically-equivalent class (`I2` and `I3`). One has a more specific method (it's a child implementation) vs the other has two equally ambiguous ones. This is also a good reason to override explicitly when you have two inherited methods with matching signatures, even if just to call one of them via `IParent.super.myMethod()` – Rogue Jun 21 '20 at 14:32
  • @Rogue It doesn't have anything to do with `I`. Even if `I` weren't there, there would be a conflict when you implement `I2` and `I3`. – Thiyagu Jun 21 '20 at 14:34
  • I'm speaking as to why `I` with a child class was being allowed, not why the other errored. We're arguing the same thing I think (method/member resolution) – Rogue Jun 21 '20 at 14:38
  • @Rogue When we have `I -> I2` I2 is more specific whereas when we have `I -> I2` and `I -> I3` and we implement I2 and I3, there arises a conflict. I think we are talking about the same thing :) – Thiyagu Jun 21 '20 at 14:42
  • I am not sure if "*most specific* default providing interface" is right term here. I thought that it meant something more along `foo(Object o){...}` `foo(Number n){...}` and if I use `foo(1)` then `foo(Number)` will be executed because `Number` is *more specific* description for `Integer` than `Object`. But in case of `class Parent{void foo(){..}}` `class Child extends Parent {@override void foo(){..} }` `class GrandChild extends Child{}` `GrandChild gc = new GrandChild(); gc.foo();` then `foo` from `Child` will be invoked because it is closest in *inheritance tree*. – Pshemo Jun 21 '20 at 14:44
  • Also in case where `interface I2 extends I` declaring `I` in `... implements I, I2` is redundant. It is effectively `implements I2`. – Pshemo Jun 21 '20 at 14:47
  • @Pshemo Method overrides are resolved at *compile* time. That is not the issue here. It is when a class inherits more than one method with the *same signature*. – Thiyagu Jun 21 '20 at 14:49