Действительно ли введение метода по умолчанию в интерфейс сохраняет обратную совместимость?
Я думаю, что я немного смущен введением методов по умолчанию для интерфейсов в Java. Насколько я понимаю, идея заключается в том, что методы по умолчанию могут быть введены в существующие интерфейсы, не нарушая существующий код.
Если я реализую интерфейс с неабстрактным классом, я (конечно) должен определить реализации всех абстрактных методов в интерфейсе. Если интерфейс определяет метод по умолчанию, я наследую реализацию этого метода.
Если я реализую два интерфейса, я, очевидно, должен реализовать объединение абстрактных методов, определенных в обоих интерфейсах. Я наследую реализацию всех методов по умолчанию; однако, если случается конфликт между методами по умолчанию в двух интерфейсах, я должен переопределить этот метод в своем реализующем классе.
Это звучит хорошо, но как насчет следующего сценария?
Предположим, есть интерфейс:
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 ;}
}
и второй интерфейс
package com.acme ;
/**
* Version 1.0
*/
public interface B {
public void bar() ;
}
Поэтому я могу написать следующее:
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());
}
}
Так что должно быть хорошо, и действительно
java com.mycompany.C
отображает результат 42.
Но теперь предположим, что acme.com вносит следующие изменения в 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;
}
}
Насколько я понимаю, внедрение этого метода должно быть безопасным. Но если я теперь запусту существующий com.mycompany.C с новой версией, я получу ошибку времени выполнения:
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)
Это не совсем удивительно, но разве это не означает, что введение методов по умолчанию в существующие интерфейсы всегда рискует сломать существующий код? Что мне не хватает?