Чи є за замовчуванням 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-February/000068.html , але це частина приватного списку розсилки, і я не можу запитати їх безпосередньо.

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


Відеосесія для перегляду тут medianetwork.oracle.com/video/player/1113272518001 Це дизайнер, який розповідає про функцію, яка називається Віртуальні розширення. Він також розповідає про те, як це не порушує зворотну сумісність.
Пітер Лорі

Отже, відповідь на мій приклад - наразі ви отримуєте помилку компілятора. Але вони відкриті для інших рішень.
Піролістичний

Іншим корисним матеріалом для цього є cr.openjdk.java.net/~briangoetz/lambda/…
MohamedSanaulla

Sidenote: остаточний синтаксис для реалізації методів інтерфейсу за замовчуванням виявився різним (блок коду замість посилання на зовнішній клас).
Йоахім Зауер,

4
Java завжди мала множинне успадкування типів . Методи за замовчуванням додають багаторазове успадкування поведінки , але не стану . (Більшість проблем успадкування держави в таких мовах, як C ++).
Брайан Гетц,

Відповіді:


66

Відповідь на повторювану операцію:

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

Я відповідаю на ваше запитання: так, це форма багаторазового успадкування, оскільки ви можете успадкувати поведінку від різних батьків. Що бракує - це успадкування станів, тобто атрибутів.


2
+1: Коли виникає конфлікт, потрібна буде більш конкретна реалізація, ніж менш конкретна, що дозволить вам вказати, якою вона повинна бути, якщо конфлікт існує.
Peter Lawrey

@ H-Man2 Я не розумію. Якщо це правда, це означає, що це порушить бінарну сумісність. Зараз, можливо, це не так погано, як порушення бінарної сумісності для запобігання багаторазовому успадкуванню, порушення бінарної сумісності відстій.
Піролістичний

@PeterLawrey, який із них є більш конкретним у моєму прикладі?
Піролістичний

@Pyrolistic: Ні, це не порушує сумісності, оскільки компілятор може перевести реалізацію за замовчуванням у звичайний виклик методу. Я думаю, що це більше макрос, ніж реальне успадкування, але може імітувати аспекти мульті-успадкування. Можливо, відео від Пітера дає більш детальну відповідь.
H-Man2,

насправді ми можемо обійти відсутні стани, маючи абстрактні геттери та сетери, клас реалізації може додавати стани ...
vikkyhacks

8

Я знаю, що це стара публікація, але оскільки я працюю з цими матеріалами ...

Ви отримаєте помилку від компілятора, повідомляючи вам, що:

 клас TimeTravelingStudent успадковує не пов’язані за замовчуванням параметри present () від типів Attendance і посилання Timeline на present є неоднозначним, як метод present () на шкалі Timeline, так і метод present () у матчі Attendance.


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, це більше схоже на рішення у стилі риси, а не на рішення стилю багаторазового успадкування.


4

Коротше кажучи: це помилка часу компіляції, вона повинна перевизначити метод вручну при реалізації.


Призначення методу за замовчуванням

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

І, multiple inheritanceяк і в C ++, насправді його слід уникати, це точно не мета методу за замовчуванням у Java.


Як замінити

2 варіанти:

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

Поради:

  • метод із інтерфейсу за замовчуванням є загальнодоступним, тому не забудьте додати publicключове слово, коли його перевизначаєте.

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.