A introdução de um método padrão em uma interface realmente preserva a compatibilidade retroativa?
Acho que estou um pouco confuso com a introdução de métodos padrão para interfaces em Java. Pelo que entendi, a idéia é que métodos padrão possam ser introduzidos em interfaces existentes sem quebrar o código existente.
Se eu implementar uma interface com uma classe não abstrata, eu (é claro) tenho que definir implementações de todos os métodos abstratos na interface. Se a interface definir um método padrão, herdo a implementação desse método.
Se eu implementar duas interfaces, obviamente tenho que implementar a união dos métodos abstratos definidos nas duas interfaces. Eu herdo a implementação de todos os métodos padrão; no entanto, se ocorrer uma colisão entre métodos padrão nas duas interfaces, devo substituir esse método na minha classe de implementação.
Parece bom, mas e o cenário a seguir?
Suponha que exista uma interface:
package com.example ;
/**
* Version 1.0
*/
public interface A {
public void foo() ;
/**
* The answer to life, the universe, and everything.
*/
public default int getAnswer() { return 42 ;}
}
e uma segunda interface
package com.acme ;
/**
* Version 1.0
*/
public interface B {
public void bar() ;
}
Para que eu possa escrever o seguinte:
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());
}
}
Então isso deve ficar bem, e de fato
java com.mycompany.C
exibe o resultado 42.
Mas agora suponha que o acme.com faça a seguinte alteração em B:
package com.acme ;
/**
* Version 1.1
*/
public interface B {
public void bar() ;
/**
* The answer to life, the universe, and everything
* @since 1.1
*/
public default int getAnswer() {
return 6*9;
}
}
Pelo que entendi, a introdução desse método deve ser segura. Mas se eu agora executar o com.mycompany.C existente na nova versão, recebo um erro de tempo de execução:
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: com/example/A.getAnswer com/acme/B.getAnswer
at com.mycompany.C.getAnswer(C.java)
at com.mycompany.C.main(C.java:12)
Isso não é totalmente surpreendente, mas isso não significa que a introdução de métodos padrão em interfaces existentes sempre corre o risco de quebrar o código existente? o que estou perdendo?