Java - реализация нескольких интерфейсов с одним и тем же методом и разными типами возврата
Рассмотрим следующий код:
public interface A {
public A another();
}
public interface B {
public B another();
}
public interface AB extends A,B {
public AB another();
}
Это приводит к ошибке компиляции на AB
:
типы B и A несовместимы; оба определяют другую (), но с несвязанными типами возврата
Я видел этот вопрос и следую примеру несовместимости в принятом ответе - т.е.
public interface C {
public void doSomething();
}
public interface D {
public boolean doSomething();
}
public interface CD extends C,D {
}
Однако в этом случае возвращаемые типы были действительно несовместимы - возвращаемый тип не может быть как void, так и логическим. Принимая во внимание, что в моем примере выше, another()
тип возврата AB
это одновременно A
и B
Таким образом, можно реализовать оба расширенных интерфейса.
Кроме того, взглянув на JLS (8.4.8, 8.4.8.3, 8.4.8.4), я не совсем понимаю, почему мой приведенный выше пример неправомерен. Кто-нибудь может мне это объяснить?
Во-вторых, есть ли какие-либо решения / обходные пути для этого, кроме повторения требований контракта A
или же B
в AB
?
1 ответ
Это сообщение об ошибке появляется для версий Java до версии 1.5 (по крайней мере, я могу воспроизвести ошибку при установке уровня соответствия 1.4 в Eclipse). Другими словами, убедитесь, что вы смотрите на достаточно старые спецификации.
На Java >= 1.5 следующее компилируется нормально.
interface A {
public A another();
}
interface B {
public B another();
}
interface AB extends A,B {
public AB another();
}
Как вы говорите, так как AB
это одновременно A
и B
, удовлетворяет оба интерфейса.
Вот цитата из спецификации языка Java (второе издание, то есть Java 1.4):
9.2 Члены интерфейса
Члены интерфейса:
- Эти члены объявлены в интерфейсе.
- Эти члены унаследованы от прямых суперинтерфейсов.
- Если интерфейс не имеет прямых суперинтерфейсов, [...]
Отсюда следует, что это ошибка времени компиляции, если интерфейс объявляет метод с той же сигнатурой и другим типом возвращаемого значения, либо с предложением о несовместимости throws.
Более того, текущая спецификация гласит следующее:
9.4.2 Перегрузка
Если два метода интерфейса (оба они объявлены в одном и том же интерфейсе или оба наследуются интерфейсом или один объявлен и один унаследован) имеют одинаковое имя, но разные сигнатуры, которые не эквивалентны переопределению (§8.4.2), то имя метода считается перегруженным. Этот факт не вызывает затруднений и сам по себе никогда не приводит к ошибке времени компиляции. Не существует обязательной связи между типами возвращаемых данных или между предложениями throws двух методов с одинаковым именем, но с разными сигнатурами, которые не эквивалентны переопределению.