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 несовместимы; оба определяют другое(), но с несвязанные типы возврата

Я видел этот вопрос SO и следую примеру несовместимости в принятом ответе - i.e.

public interface C { 
  public void doSomething();
}

public interface D {
  public boolean doSomething();
}

public interface CD extends C,D { 
}

Однако в этом случае типы возврата были действительно несовместимы - тип возврата не может быть как void, так и boolean. Принимая во внимание, что в приведенном выше примере возвращаемый тип another() AB является как A, так и B, поэтому возможно реализовать оба расширенных интерфейса.

Кроме того, посмотрев JLS (8.4.8, 8.4.8.3, 8.4.8.4), я не совсем понимаю, почему мой пример выше незаконно. Может кто-нибудь объяснить это мне?

Во-вторых, существуют ли какие-либо решения/обходные пути для этого, кроме повторения контрактных требований A или B в AB?

Ответ 1

Это сообщение об ошибке появляется для версий до версии 1.5 Java (по крайней мере, я могу воспроизвести ошибку при установке уровня соответствия 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), то имя метода считается перегруженным. Этот факт не вызывает затруднений и никогда сам по себе не приводит к ошибке времени компиляции. Между типами возврата или между предложениями бросков двух методов с тем же именем нет требуемой взаимосвязи, но разные подписи, которые не являются эквивалентными.