Множественная неоднозначность наследования с интерфейсом

Мы все знаем о проблеме алмаза относительно множественного наследования -

   A
  / \
 B   C
  \ / 
   D

Эта проблема описывает неоднозначную ситуацию для класса D. Если класс A имеет метод, и оба/из B и/или C переопределяют метод, а какая версия метода D переопределяет?

Является ли эта проблема применимой и для интерфейсов в Java? Если нет, как интерфейсы Java справляются с этой проблемой?

Ответ 1

Проблема с алмазом применяется только к наследованию реализации (extends во всех версиях Java до Java 8). Это не относится к наследованию API (implements во всех версиях Java до Java 8).

Поскольку методы интерфейса с сигнатурами типа соответствия совместимы, проблема с алмазом отсутствует, если вы дважды наследуете одну и ту же подпись метода: вместо этого подписи сигнатур метода просто сливаются. (И если подписи типов не совпадают, то у вас также нет проблемы с алмазом.)

В Java 7 и ниже единственным способом наследования кода реализации было использование ключевого слова extends, которое ограничивает не более одного родителя. Поэтому нет наследования множественных реализаций и проблемы с алмазом не существует.

Java 8 добавляет новую морщину, потому что она позволяет интерфейсам иметь код реализации. Он все еще избегает проблемы с алмазом, просто отступая от предыдущего поведения (без наследования реализации), когда вы реализуете несколько интерфейсов с методами, имеющими соответствующие подписи.

Ответ 2

Java преодолевает эту проблему, даже если интерфейсы могут иметь стандартные реализации методов, поскольку реализация по умолчанию либо однозначна (одна в классе A), либо ситуация решается некоторым правилом (когда класс B или класс C переопределяет реализацию из класса A, см. ниже).

Когда супертипы класса или интерфейса предоставляют несколько методов по умолчанию с одинаковой сигнатурой:

  • Методы экземпляров предпочтительнее, чем методы интерфейса по умолчанию.
  • Методы, которые уже переопределены другими кандидатами, игнорируются. Это обстоятельство может возникнуть, когда супертипы имеют общий предок.

Однако, если конфликтуют два или более независимых метода по умолчанию, или метод по умолчанию конфликтует с абстрактным методом, тогда компилятор Java создает ошибку компилятора. Вы должны явно переопределить методы супертипа. В этом случае вы можете вызывать любую из реализаций по умолчанию с ключевым словом super.

См. также: Как работает новая модель интерфейса Java 8 (включая алмаз, множественное наследование и приоритет)?

Ответ 3

Java не поддерживает множественное наследование, поэтому проблема с алмазом не возникает. Если B и C являются интерфейсами, то в интерфейсах нет реализации. Даже если B и C переопределяют метод в интерфейсе A (не может быть классом), методы будут иметь одну и ту же подпись. Нет никакой двусмысленности в отношении того, какую реализацию использовать, потому что нет реализации.

Ответ 4

При использовании стандартных методов в интерфейсе, введенных в Java 8, может возникнуть проблема с несколькими наследованиями, существует 3 сценария -

1- Если реализация класса переопределяет метод по умолчанию и предоставляет свои собственные функции для метода по умолчанию, то метод класса имеет приоритет над методами интерфейса по умолчанию.

2. Когда класс реализует оба интерфейса и оба имеют один и тот же метод по умолчанию, также класс не переопределяет этот метод, тогда будет вызвана ошибка.

3 - В случае, когда интерфейс расширяет другой интерфейс, и оба имеют один и тот же метод по умолчанию, метод по умолчанию наследующего интерфейса будет иметь приоритет.

Подробнее об этом здесь.

Ответ 5

Чтобы добавить к существующим ответам о множественном наследовании Java8 с интерфейсами (a.k.a., как Java по-прежнему избегает проблемы с алмазами):

Существует три правила:

  • Класс всегда выигрывает. Реализация собственного класса класса имеет приоритет над методами по умолчанию в интерфейсах.

  • Если класс не имеет: самый определенный интерфейс выигрывает

введите описание изображения здесь

  1. Если выше не так, наследующий класс должен явно указывать используемую им реализацию метода (иначе он не будет компилироваться)

введите описание изображения здесь