Реализация двух интерфейсов в классе с тем же методом. Какой метод интерфейса переопределяется?

Два интерфейса с теми же именами методов и подписями. Но реализованный единым классом затем, как компилятор определит, какой метод для который интерфейс?

Исключая:

interface A{
  int f();
}

interface B{
  int f();
}

class Test implements A, B{   
  public static void main(String... args) throws Exception{   

  }

  @Override
  public int f() {  // from which interface A or B
    return 0;
  }
}   
222
задан Kevin Panko 12 March 2014 в 03:30
поделиться

4 ответа

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


Пример совместимости

Вот пример, где у вас есть интерфейс Gift , в котором есть метод present () (например, представление подарков), а также ] интерфейс Guest , который также имеет метод present () (например, гость присутствует, а не отсутствует).

Презентабельный Джонни одновременно Дар и Гость .

public class InterfaceTest {
    interface Gift  { void present(); }
    interface Guest { void present(); }

    interface Presentable extends Gift, Guest { }

    public static void main(String[] args) {
        Presentable johnny = new Presentable() {
            @Override public void present() {
                System.out.println("Heeeereee's Johnny!!!");
            }
        };
        johnny.present();                     // "Heeeereee's Johnny!!!"

        ((Gift) johnny).present();            // "Heeeereee's Johnny!!!"
        ((Guest) johnny).present();           // "Heeeereee's Johnny!!!"

        Gift johnnyAsGift = (Gift) johnny;
        johnnyAsGift.present();               // "Heeeereee's Johnny!!!"

        Guest johnnyAsGuest = (Guest) johnny;
        johnnyAsGuest.present();              // "Heeeereee's Johnny!!!"
    }
}

Приведенный выше фрагмент компилируется и запускается.

Обратите внимание, что необходим только один @Override !!! . Это связано с тем, что Gift.present () и Guest.present () являются « @Override -эквивалентными» ( JLS 8.4.2 ).

Таким образом, Джонни имеет только одну реализацию из present () , и неважно, как вы относитесь к Джонни , будь то Gift или Гость , есть только один метод для вызова.


Пример несовместимости

Вот пример, в котором два унаследованных метода НЕ @Override -эквивалентны:

public class InterfaceTest {
    interface Gift  { void present(); }
    interface Guest { boolean present(); }

    interface Presentable extends Gift, Guest { } // DOES NOT COMPILE!!!
    // "types InterfaceTest.Guest and InterfaceTest.Gift are incompatible;
    //  both define present(), but with unrelated return types"
}

Это еще раз подтверждает, что наследование членов от интерфейса должно подчиняться общее правило объявления членов. Здесь у нас есть Gift и Гость , определяют present () с несовместимыми типами возврата: один void другой логический . По той же причине, что вы не можете использовать void present () и boolean present () в одном типе, этот пример приводит к ошибке компиляции.


Резюме

Вы можете наследовать методы, которые @Override -эквивалентны, при условии соблюдения обычных требований переопределения и скрытия методов. Поскольку они ЯВЛЯЮТСЯ @Override -эквивалентными, фактически существует только один метод, который нужно реализовать, и поэтому нет ничего, из чего можно было бы отличить / выбрать.

Компилятору не нужно определять, какой метод предназначен для какого интерфейса, потому что, если они определены как @Override -эквивалентные, это один и тот же метод.

Устранение потенциальных несовместимостей может быть сложной задачей, но это уже другая проблема.

Ссылки

312
ответ дан 23 November 2019 в 04:02
поделиться

Что касается компилятора, то эти два метода идентичны. Будет одна реализация обоих.

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

20
ответ дан 23 November 2019 в 04:02
поделиться

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

Однако, если семантические контракты двух интерфейсных методов противоречат друг другу, вы практически проиграли; тогда вы не можете реализовать оба интерфейса в одном классе.

12
ответ дан 23 November 2019 в 04:02
поделиться

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

3
ответ дан 23 November 2019 в 04:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: