Являются ли значения по умолчанию в JDK 8 формой множественного наследования в Java?

83

Новая функция, входящая в JDK 8, позволяет добавлять к существующему интерфейсу, сохраняя двоичную совместимость.

Синтаксис похож на

public interface SomeInterface() {
  void existingInterface();
  void newInterface() default SomeClass.defaultImplementation;
}

Таким образом, для всех существующих реализаций, SomeInterfaceкогда они обновляются до этой новой версии, они не все внезапно обнаруживают ошибки компиляции newInterface().

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

public interface Attendance {
   boolean present() default DefaultAttendance.present;
}

public interface Timeline {
   boolean present() default DefaultTimeline.present;
}

public class TimeTravelingStudent implements Attendance, Timeline {

}

// which code gets called?
new TimeTravelingStudent().present();

Было ли это определено как часть JDK 8?

Я обнаружил, что боги Java говорят о чем-то похожем здесь http://cs.oswego.edu/pipermail/lambda-lib/2011-Feb February/000068.html , но это часть частного списка рассылки, и я не могу спросить их напрямую.

См. Дополнительные сведения о том, как будут использоваться значения по умолчанию в JDK 8 и расширить интерфейс Collection для поддержки лямбда-выражений: https://oracleus.wingateweb.com/published/oracleus2011/sessions/25066/25066_Cho223662.pdf

Пиролитический
источник
Видеосеанс для просмотра находится здесь medianetwork.oracle.com/video/player/1113272518001 Это дизайнер говорит о функции, называемой виртуальными расширениями. Он также говорит о том, что это не нарушает обратную совместимость.
Питер Лоури,
Итак, ответ на мой пример: в настоящее время вы получаете ошибку компилятора. Но они открыты для других решений.
Pyrolistical
Еще один полезный материал для этого - cr.openjdk.java.net/~briangoetz/lambda/…
MohamedSanaulla,
Замечание: окончательный синтаксис для реализаций методов интерфейса по умолчанию оказался другим (блок кода вместо ссылки на внешний класс).
Иоахим Зауэр
4
В Java всегда было множественное наследование типов . Методы по умолчанию добавляют множественное наследование поведения , но не состояния . (Множественное наследование состояния в таких языках, как C ++, является источником большинства проблем.)
Брайан Гетц

Ответы:

66

Ответ на дублирующую операцию:

Чтобы решить проблему множественного наследования, класс, реализующий два интерфейса, обеспечивающих реализацию по умолчанию для одного и того же имени и сигнатуры метода, должен предоставлять реализацию метода. [Полная статья]

Мой ответ на ваш вопрос: да, это форма множественного наследования, потому что вы можете унаследовать поведение от разных родителей. Чего не хватает, так это наследования состояний, т. Е. Атрибутов.

H-Man2
источник
2
+1: при возникновении конфликта потребуется более конкретная реализация по сравнению с менее конкретной, что позволит вам указать, какой из них должен быть в случае конфликта.
Питер Лоури,
@ H-Man2 Я не понимаю. Если это правда, это означает, что это нарушит двоичную совместимость. Возможно, это не так уж плохо, как нарушение двоичной совместимости для предотвращения множественного наследования, нарушение двоичной совместимости - отстой.
Pyrolistical
@PeterLawrey, какой из них более конкретен в моем примере?
Pyrolistical
@Pyrolistical: Нет, это не нарушает совместимость, потому что компилятор может преобразовать реализацию по умолчанию в обычный вызов метода. Я думаю, что это скорее макрос, чем реальное наследование, но он может моделировать аспекты множественного наследования. Может быть, видео из Питера дает более подробный ответ.
H-Man2
на самом деле мы можем обойти отсутствующие состояния, имея абстрактные геттеры и сеттеры, реализующий класс может добавлять состояния ...
vikkyhacks 08
8

Я знаю, что это старый пост, но поскольку я работаю с этим ...

У вас будет ошибка компилятора, сообщающая вам, что:

 класс TimeTravelingStudent наследует несвязанные значения по умолчанию для present () от типов Attendance, а ссылка на временную шкалу неоднозначна, и метод present () на временной шкале, и метод present () в совпадении посещаемости.

Энкк
источник
7

Возможны два сценария:

1) Во-первых, это было упомянуто там, где нет конкретного интерфейса

public interface A {
   default void doStuff(){ /* implementation */ }
}

public interface B {
   default void doStuff() { /* implementation */ } 
}

public class C implements A, B {
// option 1: own implementation
// OR
// option 2: use new syntax to call specific interface or face compilation error
  void doStuff(){
      B.super.doStuff();
  }
}

2) Во-вторых, когда ЕСТЬ более конкретный интерфейс:

   public interface A {
       default void doStuff() { /* implementation */ } 
    }

    public interface B extends A {
       default void doStuff() { /* implementation */ } 
    }

    public class C implements A, B {
    // will use method from B, as it is "closer" to C
    }
Андрейс
источник
4

Мой ответ на ваш вопрос: да, это форма множественного наследования, потому что вы можете унаследовать поведение от разных родителей. Чего не хватает, так это наследования состояний, т. Е. Атрибутов.

Да, но вы можете добавить в свой интерфейс методы получения и установки, которые затем должны реализовать классы реализации. Тем не менее, реализующие классы не наследуют атрибуты. Итак, AFAICS, это больше похоже на решение в стиле признака, а не на решение в стиле множественного наследования.

OlliP
источник
4

Вкратце: это ошибка времени компиляции, она должна вручную переопределить метод в реализации.


Назначение метода по умолчанию

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

И, multiple inheritanceкак и в C ++, на самом деле следует избегать, это определенно не цель метода по умолчанию в Java.


Как переопределить

2 варианта:

  • Переопределите метод с его собственной логикой.
  • Переопределите метод, вызовите один из методов интерфейса через superформат:<interface_name>.super.<method_name>();

Подсказки:

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

Если кто-то все еще ищет ответ, если класс реализует два интерфейса с одним и тем же методом по умолчанию, тогда классу необходимо разрешить неоднозначность, предоставив собственную реализацию. Посмотрите это руководство, чтобы узнать больше о том, как работает наследование в методах по умолчанию.

митил-учеба
источник
0

«Как мы будем различать методы» - это вопрос, который был задан Stackoverflow и относился к этому вопросу: конкретные методы в интерфейсах Java1.8.

Ниже приводится пример, который должен ответить на этот вопрос:

interface A{
default public void m(){
System.out.println("Interface A: m()");
}
}

interface B{
default public void m(){
System.out.println("Interface B: m()");
}
}

 class C implements A,B { 

 public void m(){
  System.out.println("Concrete C: m()");   
 }

public static void main(String[] args) {
   C aC = new C();
   aC.m();
   new A(){}.m();
   new B(){}.m();
}
}

Класс C выше должен реализовывать свой собственный конкретный метод интерфейсов A и B. А именно:

 public void m(){
  System.out.println("Interface C: m()");   
 }

Для вызова реализации бетона в виде метода из определенного интерфейса , вы можете создать экземпляр в интерфейсе и явно вызывать на метод бетонного этого интерфейса

Например, следующий код вызывает конкретную реализацию метода m () из интерфейса A :

new A(){}.m();

Результатом выше будет:

Интерфейс A: m ()

Марк Берли
источник
-1

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

Питер
источник