Решают ли интерфейсы проблему «смертельного алмаза смерти»? - PullRequest
5 голосов
/ 25 марта 2012

Решают ли интерфейсы проблему смертельный алмаз смерти ?

Не думаю, например:

// A class implementing two interfaces Interface1 and Interface2.
// Interface1 has int x=10 and Interface2 has int x = 20

public class MultipleInterface implements Interface1, Interface2{

    public void getX(){
        System.out.println(x);
    }
}

Здесь мы получаем неоднозначное x.

Хотя интерфейсы являются хорошим способом решения неоднозначности методов, я полагаю, что они не работают в случае переменных?

Я прав?Если я что-то упустил, просветите меня.

Ответы [ 6 ]

12 голосов
/ 25 марта 2012

Когда класс наследует две переменные от родительских интерфейсов, Java настаивает на том, чтобы любое использование рассматриваемого имени переменной было полным. Это решает проблему. См. раздел спецификации языка Java 8.3 :

Класс может наследовать более одного поля с одним и тем же именем. Такая ситуация сама по себе не вызывает ошибку во время компиляции. Однако любая попытка в теле класса ссылаться на любое такое поле по его простому имени приведет к ошибке времени компиляции, потому что такая ссылка неоднозначна.

Аналогичное утверждение применяется в отношении интерфейсов ( JLS §9.3 ).

Пример кода в ответ Оскара Лопеса превосходен. Вот еще один пример:

class Base {
    int x = 10;
}

interface Interface {
    int x = 20;
}

class SingleInheritance implements Interface {
    int y = 2 * x; // ok
}

class MultipleInheritance extends Base implements Interface {
    int y = 2 * x; // compile-time error
    int z = 2 * Interface.x; // ok
}

void aMethod(MultipleInheritance  arg) {
    System.out.println("arg.x = " + arg.x); // compile-time error
    System.out.println("x = " + Interface.x); // ok
}

Редактировать

Java 8 представляет ограниченную форму множественного наследования для методов, потому что интерфейсы теперь могут объявлять методы по умолчанию , которые могут наследовать подынтерфейсы и реализующие классы. Поскольку класс может реализовывать несколько интерфейсов, это может привести к неоднозначности, поскольку различные методы по умолчанию с одной и той же сигнатурой могут быть унаследованы от нескольких интерфейсов. 1 Java имеет дело с этим, используя схему приоритетов, чтобы указать, какой метод по умолчанию фактически наследуется. , Это требует явного переопределения унаследованных методов по умолчанию, когда схема приоритета не может привести к единственному победителю.

Обратите внимание, что ни в коем случае Java не имеет проблемы Diamond, которая является очень специфическим подклассом проблем, которые могут иметь множественное наследование. 2 Часть "Diamond" относится к форме наследования класса диаграмма, которая требуется для того, чтобы иметь проблему. В C ++ проблема Diamond может возникнуть, если класс A наследует от двух классов B и C, каждый из которых наследует от общего базового класса D. В этом случае любые открытые члены D в конечном итоге появляются дважды в A - один раз наследуются через B и один раз через C. Кроме того, всякий раз, когда экземпляр A создается или уничтожается, конструктор или деструктор для D в конечном итоге вызывается дважды (часто с катастрофическими последствиями, отсюда и часть «смерти» имени). C ++ решает эти проблемы, предоставляя виртуальное наследование . (Подробнее см. Обсуждение здесь .)

1 Обратите внимание на использование слова «отчетливый». Нет проблем, если тот же самый метод по умолчанию наследуется через два родительских интерфейса, которые, в свою очередь, расширяют общий базовый интерфейс, в котором определен метод по умолчанию; метод по умолчанию просто наследуется.

2 Другие проблемы множественного наследования - такие как неоднозначности, которые могут возникать в Java с полями интерфейса, статическими методами и методами по умолчанию - технически не имеют ничего общего с проблемой Diamond (фактически, Проблема Смертельного Алмаза Смерти). Однако большая часть литературы по этому вопросу (и более ранняя версия этого ответа) в конечном итоге сводит все проблемы множественного наследования под рубрикой «Алмаз смерти». Полагаю, название слишком крутое, чтобы использовать его только в технически приемлемых случаях.

11 голосов
/ 25 марта 2012

Интерфейс не может иметь атрибутов.Когда вы пишете это:

public interface Foo {
    int x;
}

Под капотом оно неявно преобразуется в константу, что-то вроде этого:

public interface Foo {
    public static final int x;
}

Допустим, у вас есть другой интерфейс с аналогично названной константой:

public interface Bar {
    int x;
}

И если вы будете использовать значение x в классе, который реализует как Foo, так и Bar, вам придется квалифицировать эти константы, не оставляя места для неясностей, как это:

public class Baz implements Foo, Bar {
    private int y = Foo.x + Bar.x;
}

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

5 голосов
/ 25 марта 2012

Нет, нет.Интерфейсы не имеют никаких переменных, кроме статических финальных.

Если вы действительно напишите, скомпилируете и выполните эти интерфейсы и классы, у вас будет ответ.Эта переменная x не является членом класса, поэтому нет никакой двусмысленности.

Это один из тех вопросов, на которые вы легко можете ответить, написав код и сообщив JDK.Это будет быстрее, чем спрашивать здесь.

3 голосов
/ 31 марта 2012

Java противостоит множественному наследованию конкретного / абстрактного класса, но не множественному наследованию интерфейса, где вы наследуете абстрактные методы, а не реализацию, лучший пост с хорошим объяснением и примерами http://www.tech -knowledgy.com / interfaces-sovles-diamond-death/

0 голосов
/ 02 апреля 2013

Deadly Diamond of Death - это проблема с переменными, но еще больше проблема с виртуальными методами.Если классы Moo1 и Moo2 должны оба наследовать от класса Foo и переопределять абстрактную виртуальную функцию Bar, и если классу Zoo было разрешено наследовать от Moo1 и Moo2, без необходимостидобавьте свое собственное переопределение Bar, было бы неясно, какой метод Bar из Zoo должен делать.Интерфейсы избегают этой проблемы, требуя, чтобы каждый класс, который реализует интерфейс, предоставлял свою собственную реализацию для всех членов интерфейса, и определяя, что все члены интерфейса будут считаться идентичными во всех интерфейсах, которые расширяют его непосредственно или косвенно.Таким образом, в описанной выше ситуации, если бы Foo и т. Д. Были интерфейсами, а не классами, тогда любой класс, который реализует Zoo, потребовал бы реализации Foo.Bar, что было бы синонимом Moo1.Bar, Moo2.BarZoo.Bar.

0 голосов
/ 02 апреля 2013

Проблема Смертельного Алмаза Смерти.

class A
{
void eat()
{

}
}

Классы B и C расширяют метод A и Override eat ()

class B extends A
{
void eat()
{
}
}


class C extends A
{
void eat()
{
}
}

теперь, если у нас есть множественное Наследование, что произойдет в следующемдело.

 class D extends B ,C
{
//which eat() method will be inherited here for class D ? a problem  ? ?
}
...