Search This Blog

Wednesday, 28 October 2015

Interfaces and Default Methods

In an earlier post, I covered one of Java 8's new features - default methods in interfaces. While I did the pros there were some corner cases to be considered when implementing this feature.
Consider that we have an interface A:
interface A {
   default String display(String s) {
      return s.toLowerCase()+"__";
   }
}
Now I have another interface B that extends from A:
interface B extends A {
   default String display(String s) {
      return s.toLowerCase()+"%%";
   }
}
It also overrides the method. Now I added a third interface C, that extends from B. Since C extends from both A and B, which implementation of the method display() will C receive ?
public static void main(String[] args) {
  System.out.println(new C(){}.display("HELLO"));
}
   
interface C extends B {
   //which version will display() execute ?
}
If I run the main method then the output is as below:
hello%%
This makes sense, as B is the closest to C in the chain, and therefore C gets the method implementation provided by B. This is same as the rules seen with class inheritance. Now consider the below scenario:
interface A {
   default String display(String s) {
      return s.toLowerCase()+"__";
   }
}

interface B  {
   default String display(String s) {
      return s.toLowerCase()+"%%";
   }
}

interface C extends A, B {
   //which version will display() execute ?
}
This is a multiple inheritance scenario. Both A and B are independent interfaces and C extends both of them. Which version will C inherit now ?
The above code will throw a compiler error -

Duplicate default methods named display with the parameters (String) and (String) 
are inherited from the types B and A
The fix to the issue is to tell the compiler which version of the method must C inherit (This is kind of different to what is done in C++ , where we see the scope resolution operator :: or use explicit casting)
interface C extends A, B {

   @Override
   default String display(String s) {
      return A.super.display(s);
   }
}
Here we have to override the display() method and delegate the call to one of the interfaces. On running the code now:
hello__
This is also a new use case for the super keyword - something that we have only associated with classes till now.

No comments:

Post a Comment