Подтвердить что ты не робот

Реализация двух интерфейсов с двумя стандартными методами одной и той же сигнатуры в 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());
    }
}
4b9b3361

Ответ 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 без нарушения реализации.

Понятно, что они не позволяют методам компилироваться без структуры наследования через расширение, потому что разработчик библиотеки может потенциально захватить поведение.

Однако у этого есть потенциал, чтобы победить себя. Если класс реализует два интерфейса, которые не связаны с иерархическим представлением, но оба определяют одну и ту же подпись по умолчанию, тогда класс, который расширяет оба интерфейса, не будет компилироваться. (как показано выше)

Можно предположить, что два разных разработчиков библиотеки могли бы принять решение добавлять методы по умолчанию в разное время, используя общие подписи; на самом деле, вероятно, это произойдет в библиотеках, которые реализуют подобные концепции, такие как математические библиотеки. Если вам повезет, что вы используете оба интерфейса в одном классе, вы будете нарушены при обновлении.