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接口以支持lambda的详细信息,请参见以下内容:https : //oracleus.wingateweb.com/published/oracleus2011/sessions/25066/25066_Cho223662.pdf


要观看的视频会话在此处,medianetwork.oracle.com/ video/ player/1113272518001这是设计人员在谈论称为虚拟扩展的功能。他还谈到了这不会破坏向后兼容性。
彼得·劳瑞

因此,我的示例的答案是当前出现编译器错误。但是它们对其他解决方案持开放态度。
2011年


旁注:事实证明,接口方法的默认实现的最终语法是不同的(代码块而不是对外部类的引用)。
约阿希姆·绍尔

4
Java一直具有类型的多重继承。默认方法增加了行为的多重继承,但没有状态的多重继承。(大多数麻烦源于C ++等语言中的状态多重继承。)
Brian Goetz 2014年

Answers:


66

重复操作的答案是:

为了解决多重继承问题,实现两个接口的类提供了针对相同方法名称的默认实现,并且签名必须提供该方法的实现。[全文]

我对您的问题的回答是:是的,它是多重继承的一种形式,因为您可以从不同的父母那里继承行为。缺少的是继承状态,即属性。


2
+1:发生冲突时,将采用较具体的实现而不是较具体的实现,从而允许您指定发生冲突时应采用哪种实现。
彼得·劳瑞

@ H-Man2我不明白。如果是这样,则意味着它将破坏二进制兼容性。现在,也许还不如破坏二进制兼容性以防止多重继承,破坏二进制兼容性很糟糕。
火热

@PeterLawrey在我的示例中哪个更具体?
2011年

@Pyrolistical:不,它不会破坏兼容性,因为编译器可以将默认实现转换为常规方法调用。我认为它比真正的继承更多是宏,但是可以模拟多继承的各个方面。也许来自Peter的视频提供了更详细的答案。
H-Man2

实际上,我们可以通过使用抽象的getter和setter来解决丢失的状态,实现类可以添加状态……
vikkyhacks

8

我知道这是一篇旧文章,但是由于我正在处理这些东西...

您将在编译器中看到一个错误,告诉您:

Time类TimeTravelingStudent从Attendance和Timeline类型的present()继承对present()的不相关默认值,对present的引用是模棱两可的,时间轴中的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

我对您的问题的回答是:是的,它是多重继承的一种形式,因为您可以从不同的父母那里继承行为。缺少的是继承状态,即属性。

是的,但是您可以将getter和setter添加到实现类必须实现的接口中。但是,实现类不会继承属性。因此,对于AFAICS,它更像是一种特征样式解决方案,而不是多重继承样式解决方案。


4

简而言之:这是一个编译时错误,必须在实现中手动覆盖该方法。


默认方法的目的

在Java 8中引入默认方法的主要目的是使接口可扩展而不破坏现有的实现(有太多的第三方Java库)。

multiple inheritance像在C ++实际上是旨在避免的,这绝对不是在Java默认方法的目的。


如何覆写

2种选择:

  • 用自己的逻辑覆盖该方法。
  • 覆盖方法,通过调用接口的方法之一super,格式为:<interface_name>.super.<method_name>();

提示:

  • 接口的method方法默认为public,因此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()");   
 }

呼吁具体实施一的方法,从一个特定的接口,你可以实例化接口显式调用具体方法是的接口

例如,以下代码从接口A调用方法m()具体实现:

new A(){}.m();

上面的输出将是:

接口A:m()


-1

据我所知,它不是多重继承,因为它们是无状态的。因此,虚拟扩展方法不支持完整的对象或类功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.