Я думаю, что меня немного смущает введение методов по умолчанию для интерфейсов в 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)
Это не совсем удивительно, но разве это не означает, что внедрение методов по умолчанию для существующих интерфейсов всегда сопряжено с риском нарушения существующего кода? Что мне не хватает?