Default methods are used as sort of back-up methods, meaning that they will only be called if there is no concrete implementation of that method.
When looking at your class, we have this encounter order:
GImpl
, which callsprint()
.GImpl
has noprint()
, so going up the tree.M
does have aprint()
, so using that one.
The only place where I see you using G
is as the variable type, which is completely fine, as GImpl
is-a G
.
If you had wanted to call G
's method, then consider the following:
interface G {
default void print() {
System.out.println("G");
}
}
class M {
}
class GImpl extends M implements G {}
public class Weird {
public static void main(String[] args) {
G g=new GImpl();
g.print();
}
}
Here, we have the following order:
GImpl
, which callsprint()
.GImpl
has noprint()
, so going up.M
does not haveprint()
, going up.- Only have
G
left, which has a default implementation ofprint()
, so gets called. Note: If this was absent, your code would not even compile.
So with default methods you cannot override already existing behaviour. You can however add behaviour when no other behaviour was in place yet.