Реализация двух интерфейсов с двумя стандартными методами одной и той же сигнатуры в Java 8
Предположим, что у меня есть два интерфейса:
public interface I1
{
default String getGreeting() {
return "Good Morning!";
}
}
public interface I2
{
default String getGreeting() {
return "Good Afternoon!";
}
}
Если я хочу реализовать оба из них, какая реализация будет использоваться?
public class C1 implements I1, I2
{
public static void main(String[] args)
{
System.out.println(new C1().getGreeting());
}
}
Ответы
Ответ 1
Это ошибка времени компиляции. У вас не может быть двух реализаций из двух интерфейсов.
Однако, это правильно, если вы реализуете метод getGreeting
в C1
:
public class C1 implements I1, I2 // this will compile, bacause we have overridden getGreeting()
{
public static void main(String[] args)
{
System.out.println(new C1().getGreeting());
}
@Override public String getGreeting()
{
return "Good Evening!";
}
}
Я просто хочу добавить, что даже если метод в I1 является абстрактным, а по умолчанию в I2, вы не можете реализовать оба из них. Таким образом, это также ошибка времени компиляции:
public interface I1
{
String getGreeting();
}
public interface I2
{
default String getGreeting() {
return "Good afternoon!";
}
}
public class C1 implements I1, I2 // won't compile
{
public static void main(String[] args)
{
System.out.println(new C1().getGreeting());
}
}
Ответ 2
Это не относится к вопросу. Но я все же думаю, что это добавляет некоторую ценность контексту. В дополнение к ответу @toni77, я хотел бы добавить, что метод по умолчанию может быть вызван из класса реализации, как показано ниже. В приведенном ниже коде метод по умолчанию getGreeting()
из interface I1
вызывается из переопределенного метода:
public interface I1 {
default String getGreeting() {
return "Good Morning!";
}
}
public class C1 implements I1, I2 {
@override
public String getGreeting() {
return I1.super.getGreeting();
}
}
Ответ 3
Если класс реализует 2 интерфейса, оба из которых имеют метод по умолчанию java-8 с одной и той же сигнатурой (как в вашем примере), класс реализации обязателен для переопределения метода. Класс может по-прежнему использовать метод по умолчанию, используя I1.super.getGreeting();
. Он может получить доступ либо к обоим, либо к никому. Таким образом, следующая допустимая реализация C1
public class C1 implements I1, I2{
public static void main(String[] args)
{
System.out.println(new C1().getGreeting());
}
@Override //class is obliged to override this method
public String getGreeting() {
//can use both default methods
return I1.super.getGreeting()+I2.super.getGreeting();
}
public String useOne() {
//can use the default method within annother method
return "One "+I1.super.getGreeting();
}
public String useTheOther() {
//can use the default method within annother method
return "Two "+I2.super.getGreeting();
}
}
Ответ 4
Существует случай, когда это действительно работает в соответствии с правилами разрешения. Если один из интерфейсов расширяет один из других.
Используя пример сверху:
public interface I2 extends I1 {
default String getGreeting() {
return "Good Afternoon!";
}
}
Результат:
Добрый день!
Однако, я считаю, что это будет большой проблемой. Вся причина для интерфейсов по умолчанию заключается в том, чтобы позволить разработчикам библиотек развивать apis без нарушения реализации.
Понятно, что они не позволяют методам компилироваться без структуры наследования через расширение, потому что разработчик библиотеки может потенциально захватить поведение.
Однако у этого есть потенциал, чтобы победить себя. Если класс реализует два интерфейса, которые не связаны с иерархическим представлением, но оба определяют одну и ту же подпись по умолчанию, тогда класс, который расширяет оба интерфейса, не будет компилироваться. (как показано выше)
Можно предположить, что два разных разработчиков библиотеки могли бы принять решение добавлять методы по умолчанию в разное время, используя общие подписи; на самом деле, вероятно, это произойдет в библиотеках, которые реализуют подобные концепции, такие как математические библиотеки. Если вам повезет, что вы используете оба интерфейса в одном классе, вы будете нарушены при обновлении.