Java - реализация нескольких интерфейсов с одним и тем же методом и разными типами возврата

Рассмотрим следующий код:

public interface A {
  public A another();
}

public interface B {
  public B another();
}

public interface AB extends A,B {
  public AB another();
}

Это приводит к ошибке компиляции на AB:

типы В и А несовместимы; оба определяют другую(), но с несвязанными возвращаемыми типами

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

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?


person amaidment    schedule 05.07.2012    source источник
comment
Предоставленный вами код должен нормально компилироваться. Вы уверены, что у вас есть return AB another(); в интерфейсе AB? возвращаемый тип должен быть AB, иначе он не скомпилируется.   -  person RP-    schedule 05.07.2012


Ответы (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.

Более того, спецификация current говорит следующее:

9.4.2 Перегрузка

Если два метода интерфейса (оба объявлены в одном и том же интерфейсе, или оба унаследованы интерфейсом, или один объявленный и один унаследованный) имеют одно и то же имя, но разные сигнатуры, которые не эквивалентны переопределению (§8.4.2), то имя метода считается перегруженным. Этот факт не вызывает затруднений и сам по себе никогда не приводит к ошибке времени компиляции. Между возвращаемыми типами или между предложениями throws двух методов с одинаковыми именами, но разными сигнатурами, которые не эквивалентны переопределению, нет обязательной связи.

person aioobe    schedule 05.07.2012
comment
Я компилировал с 1.6 (в IDE). Я только что попытался скомпилировать это с помощью jdk 1.6.0_30 в командной строке и получил ту же ошибку компилятора. Однако он успешно скомпилировался с 1.7.0_1. - person amaidment; 05.07.2012
comment
Это интересно. Если поведение отличается, могу поспорить, что есть отчет об ошибке в любом из двух компиляторов. - person aioobe; 05.07.2012
comment
Удалось ли вам скомпилировать этот код? Если да, то какую версию Java вы использовали? - person amaidment; 05.07.2012
comment
Я скомпилировал его с помощью Eclipse 3.7. - person aioobe; 05.07.2012
comment
Согласно обсуждению здесь (отчет об ошибке Eclipse JDT) это javac ошибка. - person aioobe; 05.07.2012
comment
Спасибо - это убедительно свидетельствует о том, что это была ошибка javac. Действительно, один из комментариев к этому отчету об ошибке заключался в том, что эта проблема также поднималась в Sun, но мои поиски в базе данных ошибок Sun/Oracle не дали ее. Итак... может пора переходить на Java 7... - person amaidment; 05.07.2012