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

java interface overriding

138748 просмотра

7 ответа

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

Пример:

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;
  }
}   
Автор: Jothi Источник Размещён: 12.11.2019 09:29

Ответы (7)


310 плюса

Решение

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


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

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

Presentable johnnyэто Giftи а Guest.

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 ).

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


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

Вот пример, где два унаследованных метода НЕ @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"
}

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


Резюме

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

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

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

Рекомендации

Автор: polygenelubricants Размещён: 14.05.2010 08:03

22 плюса

Это было помечено как дубликат этого вопроса https://stackoverflow.com/questions/24401064/understanding-and-solving-the-diamond-problems-in-java

Вам нужна Java 8, чтобы получить проблему множественного наследования, но она все еще не является проблемой diamon как таковой.

interface A {
    default void hi() { System.out.println("A"); }
}

interface B {
    default void hi() { System.out.println("B"); }
}

class AB implements A, B { // won't compile
}

new AB().hi(); // won't compile.

Как комментирует JB Nizet, вы можете исправить это, мое превосходство.

class AB implements A, B {
    public void hi() { A.super.hi(); }
}

Тем не менее, у вас нет проблем с

interface D extends A { }

interface E extends A { }

interface F extends A {
    default void hi() { System.out.println("F"); }
}

class DE implement D, E { }

new DE().hi(); // prints A

class DEF implement D, E, F { }

new DEF().hi(); // prints F as it is closer in the heirarchy than A.
Автор: Peter Lawrey Размещён: 25.06.2014 05:56

20 плюса

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

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

Автор: Ash Размещён: 10.05.2010 10:29

12 плюса

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

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

Автор: Michael Borgwardt Размещён: 10.05.2010 10:31

4 плюса

Попробуйте реализовать интерфейс как анонимный.

public class MyClass extends MySuperClass implements MyInterface{

MyInterface myInterface = new MyInterface(){

/* Overrided method from interface */
@override
public void method1(){

}

};

/* Overrided method from superclass*/
@override
public void method1(){

}

}
Автор: dcanh121 Размещён: 07.10.2011 12:39

4 плюса

Как и в интерфейсе, мы просто объявляем методы, конкретный класс, который реализует эти оба интерфейса, понимает, что существует только один метод (как вы описали, оба имеют одинаковое имя в возвращаемом типе). поэтому не должно быть проблем с ним. Вы сможете определить этот метод в конкретном классе.

Но когда два интерфейса имеют метод с одинаковым именем, но с разным типом возврата, и вы реализуете два метода в конкретном классе:

Пожалуйста, посмотрите на код ниже:

public interface InterfaceA {
  public void print();
}


public interface InterfaceB {
  public int print();
}

public class ClassAB implements InterfaceA, InterfaceB {
  public void print()
  {
    System.out.println("Inside InterfaceA");
  }
  public int print()
  {
    System.out.println("Inside InterfaceB");
    return 5;
  }
}

когда компилятор получает метод "public void print ()", он сначала смотрит в InterfaceA и получает его. Но все равно он выдает ошибку времени компиляции, что тип возвращаемого значения не совместим с методом InterfaceB.

Так что это идет наперекосяк для компилятора.

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

Автор: Bhagrav Jain Размещён: 07.05.2014 10:36

3 плюса

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

Автор: Paul Whelan Размещён: 10.05.2010 10:27
Вопросы из категории :
32x32