86

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 接口以支持 lambdas 的更多详细信息,请参阅此处: https ://oracleus.wingateweb.com/published/oracleus2011/sessions/25066/25066_Cho223662.pdf

4

8 回答 8

67

重复操作的答案是:

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

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

于 2011-10-22T06:42:10.130 回答
9

我知道这是一个旧帖子,但是当我正在处理这些东西时......

您将收到编译器错误,告诉您:

 TimeTravelingStudent 类从出勤类型继承了 present() 的不相关默认值,并且 Timeline 对 present 的引用不明确,Timeline 中的方法 present() 和出勤中的方法 present() 都匹配。

于 2013-08-15T04:28:47.767 回答
8

两种情况:

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
    }
于 2017-05-11T19:34:15.860 回答
5

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


默认方法的目的

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

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


如何覆盖

2个选项:

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

提示:

  • public接口中的方法默认为public,因此在覆盖它时不要忘记添加关键字。
于 2016-07-19T05:08:13.080 回答
4

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

是的,但是您可以将 getter 和 setter 添加到实现类然后必须实现的接口。然而,实现类不继承属性。所以,AFAICS,它更像是一个特质风格的解决方案,而不是一个多重继承风格的解决方案。

于 2012-07-26T08:09:45.800 回答
3

如果有人仍在寻找答案,如果一个类使用相同的默认方法实现两个接口,那么该类需要通过提供自己的实现来解决歧义。有关默认方法中的继承如何工作的更多详细信息,请查看教程。

于 2014-08-04T06:46:23.060 回答
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()

于 2018-12-26T12:07:56.643 回答
-1

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

于 2014-01-06T16:15:54.857 回答