The default shadow method for an interface

Consider the following case:

interface IFace1 { default void printHello() { System.out.println("IFace1"); } } interface IFace2 { void printHello(); } public class Test implements IFace1, IFace2 { public static void main(String[] args) { Test test = new Test(); test.printHello(); IFace1 iface1 = new Test(); iface1.printHello(); IFace2 iface2 = new Test(); iface2.printHello(); } @Override public void printHello() { System.out.println("Test"); } } 

In the above example, I get the following output, which is quite expected.

 Test Test Test 

I read about Java-8 default methods and, in particular, about Extending interfaces containing default methods

2 nd bullet: override the default method that makes it abstract.

In the above example, where I have two interfaces that have a default method with the same name, and when I implemented both, I was able to achieve only printHello Test , which relates to IFace2 .

I have few questions about this,

  • How can I access the printHello IFace1 method, and if I cannot, why?
  • Does this not lead me from the supposed nature of IFace1 , which can now be obscured by another method?

The quote says, you can make the default abstract method in it a child interface. For instance,

 interface IFace2 extends IFace1 { void printHello(); } 

Here, when I implement IFace2 , in fact, I cannot reach the default IFace1 method, which is what happens in my case.

+6
source share
2 answers

It seems you are a little confused by the presence of the default method. So let's forget for a moment that IFace1.printHello() is the default method. So, there is a clear situation: Test implements two interfaces: IFace1 and IFace2 , which have a method with the same name and signature.

Test implements this method and therefore implements the method for both interfaces. The new default method function does not change anything about this logic. Moreover, the language developers made sure that the addition of the default method did not affect the behavior of existing code, so if your class implements the method, the presence of default methods becomes inappropriate.

However, if you write code that knows about the existence of default methods, you can call it if it is declared or inherited by a direct super-interface, that is, in your code you can use IFace1.super.printHello() to call the default IFace1 method.

The rules are not much different from the rules of superclasses. If you change the interfaces so that IFace2 expands IFace1 and still declares printHello() as an abstract method, this abstract method overrides the default method, and you cannot call IFace1.super.printHello() from inside Test anymore.

As said, these rules are not much different from ordinary instance methods. If Test declares a printHello() method, this is the only method that you can invoke with a reference to the Test instance, whether its declared type is Test , IFace1 or IFace2 . Only Test implementation methods can perform super invocations.


The main difference comes into play when possible multiple inheritance of interfaces is involved. If your Test class does not implement the printHello() method, it depends on the inheritance relationship of the two interfaces, which will happen

  • If IFace2 extends IFace1 , its abstract method overrides the default method, so a compiler error occurs because Test must implement the abstract method
  • If IFace2 does not extend to IFace1 , there are ambiguously two inherited methods with the same name and signature, therefore Test does not inherit the default method and a compiler error occurs, because Test must implement the abstract method
  • If IFace1 extends IFace2 , Test inherits the default method. It also inherits it if Test does not implement IFace2 , but this should come as a surprise ...
+7
source

How can I call the printHello method for IFace1, and if I can not, then why?

You can only do this inside an instance method of a type that implements IFace1 with

 IFace1.super.printHello(); // only if IFace1 declares a default implementation of the method 

In other words, you cannot do this with a simple reference like IFace1 or Test (or something else). This will break encapsulation.

Does this not lead me from the supposed nature of IFace1 which can now be obscured by another method?

There is no shadow. You have redefined this method, so the call is activated.

Regarding the third question, you have not expanded any interfaces, so I do not see the relevance.

If you really have

 interface IFace2 extends IFace1 { void printHello(); } 

with

 public class Test implements IFace2 { 

then you will not be able to access the implementation of the IFace1 default method. You can never skip super types to access implementations above in the inheritance hierarchy.

+4
source

All Articles