Если тип реализует два интерфейса, и каждый из них interface
определяет метод с одинаковой сигнатурой, то в действительности существует только один метод, и они не различимы. Если, скажем, два метода имеют конфликтующие типы возврата, то это будет ошибка компиляции. Это общее правило наследования, переопределения методов, скрытия и объявлений, а также применяется к возможным конфликтам не только между 2 унаследованными interface
методами, но также interface
и к супер- 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
-эквивалентные, они становятся одним и тем же методом.
Устранение потенциальных несовместимостей может быть сложной задачей, но это совсем другая проблема.
Ссылки
default
методов в Java 8.Foo
иBar
. По сути, ваш класс реализует, скажемFoo
, один из интерфейсов и предоставляетBar asBar()
метод для возврата внутреннего класса, который реализует второйBar
интерфейс. Не идеально, так как ваш класс в конечном итоге не является "баром", но в некоторых обстоятельствах он может быть полезен.Этот вопрос был отмечен как дубликат этого вопроса /programming/24401064/understanding-and-solving-the-diamond-problems-in-java
Вам нужна Java 8, чтобы получить проблему множественного наследования, но она все еще не является проблемой diamon как таковой.
Как комментирует JB Nizet, вы можете исправить это, мое превосходство.
Тем не менее, у вас нет проблем с
источник
hi()
(чтобы исправить неоднозначность). Например, реализуя его,A.super.hi()
чтобы выбрать для реализации так же, как А.Что касается компилятора, эти два метода идентичны. Там будет одна реализация обоих.
Это не проблема, если два метода эффективно идентичны, поскольку они должны иметь одинаковую реализацию. Если они отличаются по контракту (согласно документации для каждого интерфейса), у вас будут проблемы.
источник
Там нет ничего, чтобы идентифицировать. Интерфейсы только запрещают имя метода и подпись. Если оба интерфейса имеют метод с одинаковым именем и сигнатурой, реализующий класс может реализовать оба метода интерфейса с помощью одного конкретного метода.
Однако, если семантические контракты метода двух интерфейсов противоречат, вы в значительной степени проиграли; тогда вы не можете реализовать оба интерфейса в одном классе.
источник
Попробуйте реализовать интерфейс как анонимный.
источник
Как и в интерфейсе, мы просто объявляем методы, конкретный класс, который реализует оба эти интерфейса, понимает, что существует только один метод (как вы описали, оба имеют одинаковое имя в возвращаемом типе). поэтому не должно быть проблем с ним. Вы сможете определить этот метод в конкретном классе.
Но когда два интерфейса имеют метод с одинаковым именем, но с разным типом возврата, и вы реализуете два метода в конкретном классе:
Пожалуйста, посмотрите на код ниже:
когда компилятор получает метод "public void print ()", он сначала смотрит в InterfaceA и получает его. Но он все равно выдает ошибку времени компиляции, что возвращаемый тип не совместим с методом InterfaceB.
Так что это идет наперекосяк для компилятора.
Таким образом, вы не сможете реализовать два интерфейса, имеющих метод с одинаковым именем, но с другим типом возвращаемого значения.
источник
Хорошо, если они оба одинаковы, это не имеет значения. Он реализует оба из них с одним конкретным методом для каждого метода интерфейса.
источник