java - Does introducing a default method to an interface really preserve back-compatibility? -


i think i'm confused introduction of default methods interfaces in java. understand it, idea default methods can introduced existing interfaces without breaking existing code.

if implement interface non-abstract class, (of course) have define implementations of abstract methods in interface. if interface defines default method, inherit implementation of method.

if implement 2 interfaces, have implement union of abstract methods defined in both interfaces. inherit implementation of default methods; if there happens collision between default methods in 2 interfaces, must override method in implementing class.

this sounds fine, following scenario?

suppose there's interface:

package com.example ; /**  * version 1.0 */ public interface {   public void foo() ;   /**   * answer life, universe, , everything.   */   public default int getanswer() { return 42 ;} } 

and second interface

package com.acme ; /**  * version 1.0 */ public interface b {   public void bar() ; } 

so can write following:

package com.mycompany ; public class c implements com.example.a, com.acme.b {   @override   public void foo() {     system.out.println("foo");   }   @override   public void bar() {     system.out.println("bar");   }   public static void main(string[] args) {     system.out.println(new c().getanswer());   } } 

so should fine, , indeed

java com.mycompany.c  

displays result 42.

but suppose acme.com makes following change b:

package com.acme ; /**  * version 1.1 */ public interface b {   public void bar() ;   /**   * answer life, universe, ,   * @since 1.1   */   public default int getanswer() {     return 6*9;   } } 

as understand it, introducing method supposed safe. if run existing com.mycompany.c against new version, runtime error:

exception in thread "main" java.lang.incompatibleclasschangeerror: conflicting default methods: com/example/a.getanswer com/acme/b.getanswer @ com.mycompany.c.getanswer(c.java) @ com.mycompany.c.main(c.java:12) 

that's not entirely surprising, doesn't mean introducing default methods existing interfaces runs risk of breaking existing code? missing?

although adding default method same name in 2 interfaces make code fail compile, once resolve compilation error, binaries obtained after compiling both interfaces, , the class implementing interfaces, backward compatible.

so, compatibility binary compatibility. being explained in jls §13.5.6 - interface method declarations:

adding default method, or changing method abstract default, not break compatibility pre-existing binaries, may cause incompatibleclasschangeerror if pre-existing binary attempts invoke method. error occurs if qualifying type, t, subtype of 2 interfaces, , j, both , j declare default method same signature , result, , neither nor j subinterface of other.

in other words, adding default method binary-compatible change because not introduce errors @ link time, if introduces errors @ compile time or invocation time. in practice, risk of accidental clashes occurring introducing default method similar associated adding new method non-final class. in event of clash, adding method class unlikely trigger linkageerror, accidental override of method in child can lead unpredictable method behavior. both changes can cause errors @ compile time.

the reason got incompatibleclasschangeerror because, didn't recompile c class, after adding default method in b interface.

also see:


Comments

Popular posts from this blog

android - Get AccessToken using signpost OAuth without opening a browser (Two legged Oauth) -

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: mockito -

google shop client API returns 400 bad request error while adding an item -