Consider next example:
public interface A {
default void foo() { System.out.println("A.foo"); }
}
public interface B {
default void foo() { System.out.println("B.foo"); }
}
Here are two interfaces declaring default method foo with the same signature.
If you will try to extend these both interfaces in the new interface you have to make choice of two, because Java forces you to resolve this collision explicitly.
First, you can declare method foo with the same signature as abstract, which will override A and B behaviour.
public interface ABExtendsAbstract extends A, B {
@Override
void foo();
}
And when you will implement ABExtendsAbstract in the class you will have to provide foo implementation:
public class ABExtendsAbstractImpl implements ABExtendsAbstract {
@Override
public void foo() { System.out.println("ABImpl.foo"); }
}
Or second, you can provide a completely new default implementation. You also may reuse code of A and B foo methods by Accessing overridden default methods from implementing class.
public interface ABExtends extends A, B {
@Override
default void foo() { System.out.println("ABExtends.foo"); }
}
And when you will implement ABExtends in the class you will not have to provide foo implementation:
public class ABExtendsImpl implements ABExtends {}