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 двух методов с одинаковым именем, но с разными сигнатурами, которые не эквивалентны переопределению.

Другие вопросы по тегам