Ответ 1
Если тип реализует два интерфейса, и каждый interface
определяет метод, который имеет идентичную подпись, тогда на самом деле существует только один метод, и они не различимы. Если, скажем, два метода имеют конфликтующие типы возврата, то это будет ошибка компиляции. Это общее правило наследования, переопределение метода, скрытие и декларации, а также применимы также к возможным конфликтам не только между двумя унаследованными методами interface
, но также методом interface
и супер class
или даже просто конфликтами из-за стирания типов дженериков.
Пример совместимости
Вот пример, в котором у вас есть interface Gift
, который имеет метод present()
(как, например, при подаче подарков), а также interface Guest
, который также имеет метод present()
(как, например, guest присутствует и не отсутствует).
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 Johnny!!!");
}
};
johnny.present(); // "Heeeereee Johnny!!!"
((Gift) johnny).present(); // "Heeeereee Johnny!!!"
((Guest) johnny).present(); // "Heeeereee Johnny!!!"
Gift johnnyAsGift = (Gift) johnny;
johnnyAsGift.present(); // "Heeeereee Johnny!!!"
Guest johnnyAsGuest = (Guest) johnny;
johnnyAsGuest.present(); // "Heeeereee 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
define present()
с несовместимыми типами возврата: один void
другой boolean
. По той же причине, что вы не можете использовать void present()
и boolean present()
в одном типе, этот пример приводит к ошибке компиляции.
Резюме
Вы можете наследовать методы, которые @Override
-эквивалентны, с учетом обычных требований переопределения и скрытия метода. Так как они ARE @Override
-эквивалентны, эффективно реализовать только один метод, и поэтому нечего отличать/выбирать.
Компилятор не должен идентифицировать, какой метод для какого интерфейса, поскольку, как только они определены как @Override
-эквивалентные, они являются тем же самым методом.
Разрешение потенциальных несовместимостей может быть сложной задачей, но это еще одна проблема.
Ссылки
- JLS 8.4.2 Подпись метода
- JLS 8.4.8 Наследование, переадресация и скрытие
- JLS 8.4.8.3 Требования к переопределению и скрытию
- JLS 8.4.8.4 Наследование методов с переопределяющими эквивалентными сигнатурами
- "Класс может наследовать несколько методов с переопределяющими эквивалентными сигнатурами".