Являются ли значения по умолчанию в JDK 8 формой множественного наследования в Java? - PullRequest
78 голосов
/ 22 октября 2011

Новая функция, появившаяся в 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

Ответы [ 9 ]

64 голосов
/ 22 октября 2011

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

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

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

9 голосов
/ 22 октября 2011

Здесь вы можете посмотреть видео-сессию http://medianetwork.oracle.com/video/player/1113272518001 Это дизайнер, который говорит о функции, называемой виртуальными расширениями. Он также говорит о том, что это не нарушает обратную совместимость.

8 голосов
/ 15 августа 2013

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

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

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

5 голосов
/ 11 мая 2017

Существует два сценария:

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 голосов
/ 19 июля 2016

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


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

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

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


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

2 опции:

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

Советы:

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

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

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

2 голосов
/ 04 августа 2014

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

0 голосов
/ 26 декабря 2018

«Как мы будем различать методы» - это вопрос, который был задан в 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:м ()

0 голосов
/ 06 января 2014

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

...