47

Java 8 包含一个名为Defender 方法的新功能,它允许在接口中创建默认方法实现。

首先,对于所有 Java 精简程序员来说,这是一个巨大的范式转变。我查看了 Brian Goetz 提供的 JavaOne 13 演示文稿,他在其中讨论了 Collections 库中的新功能stream()parallelStream()实现。

对于在Collection接口中添加新方法,他们不可能只是添加一个新方法而不破坏以前的版本。所以他告诉我们,为了迎合这一点,添加了默认方法的新功能。

public interface SimpleInterface {
  public void doSomeWork();
   
  //A default method in the interface created using "default" keyword
  default public void doSomeOtherWork(){
    System.out.println("DoSomeOtherWork implementation in the interface");
  }
}

现在我的问题基本上是默认方法在需要向接口添加新方法而不破坏客户端代码时才有用?或者它还有其他用途吗?

4

5 回答 5

65

除了可以在未来的版本中向接口添加方法之外,还有一个重要的一点是允许interface一个功能接口,即使它有多个方法。

函数式接口只有一个可以通过 lambda 表达式实现的非默认抽象方法。一个例子是只有一个抽象方法 ( )Predicate接口test,同时提供了否定 aPredicate或将它与另一个结合的默认方法Predicate。如果没有默认方法,这些方法必须在另一个实用程序类中提供,例如 Java 8 之前的Collections类(因为您不想放弃这种 lambda 实现的可能性interface)。

于 2013-11-15T10:14:22.047 回答
25

正如您所说,主要动机是允许现有接口的演变。

但是,您也有理由希望在全新的界面中使用它们:

一个这样的原因是可以使用接口的其他(非默认)方法轻松实现的方法。为此使用default方法减少了对Foo-interface/ AbstractFoo-base-implementation 组合的需求(参见AbstractList示例)。

虽然这并没有创建一个全新的领域,但这意味着您可以拥有对最终用户友好的界面(具有许多有用的方法),同时保持其易于实现。

于 2013-11-15T10:02:10.663 回答
1

接口存在一个问题,即它们不能对扩展开放,这意味着如果需要向接口添加新方法,它将破坏这些接口的现有实现。因此,所有实现该接口的类都必须为新添加的方法提供实现,即使该方法不需要。因此,接口不容易发展。

想到的一个例子是用于 Hadoop 的 Java MapReduce API,它在 0.20.0 版本中进行了更改,以支持抽象类而不是接口,因为它们更容易发展。这意味着,可以将新方法添加到抽象类(具有默认实现),而不会破坏类的旧实现。

随着 Java 8 的发布,现在也可以在接口中添加默认方法,从而使它们也更容易发展。通过向接口添加默认方法,添加新方法,即使是接口也不会破坏预先存在的代码。

于 2015-05-05T17:11:35.130 回答
1

为了在 Collection 接口中添加新方法,他们不可能只添加一个新方法而不破坏以前的版本。

是的,他们本可以这样做,但是让我们从 API 设计者的角度来考虑,例如 Collection Library 被一些库(如 apache-commons、guava 等)使用,而这些库被许多 Java 项目使用。现在想象一下,只要在 Collection 接口中添加一个新方法就会破坏整个项目链。

现在我的问题基本上是默认方法在需要向接口添加新方法而不破坏客户端代码时才有用?或者它还有其他用途吗?

默认方法的动机/需求

API Evolution 以兼容的方式

  • 引入默认方法的最初目的是使集合库向后兼容。该库被建模为一个深层的接口层次结构,包括诸如 Collection、List、Map 和 Set 等重要成员。需要丰富它们以使 lambda 对日常编程真正有用。

为了使 Collections 库 lambda 变得丰富,Java 架构师可以重构它们以支持 lambda,但这远不是一个好的解决方案,因为它会破坏所有现有的 Java 部署和无数扩展 Collections 层次结构的第三方库

相反,java 架构师考虑引入默认方法功能以实现向后兼容性。

默认方法的用例

  • 一个重要的用例是帮助functional thinkingjava。具有默认方法的功能接口是纯行为构造。它不能保持状态。这使您的思维与函数式编程保持一致,并允许您利用编程模型所提供的功能

  • 可选方法:java 中有一些类实现了一个接口,但留下了空的方法实现,例如Iterator interface。它定义了 hasNext 和 next 以及 remove 方法。在 Java8 之前,删除被忽略,因为用户不想使用该功能。因此,许多实现 Iterator 接口的类将具有 for remove which is 的空实现unnecessary boiler plate code。使用默认方法,我们可以为这些方法提供默认实现,因此具体类不需要显式提供空实现。

  • 默认方法有助于解决java中行为的多重继承。在 Java8 之前,只支持类型的多重继承,现在在默认方法的帮助下,我们可以对行为进行多重继承。例如,Java 8 有三个规则来解决多继承引起的歧义冲突:

    • 首先,类或超类中的显式方法声明优先于任何默认方法声明。
    • 否则,选择最具体的默认提供接口中具有相同签名的方法。
    • 最后,如果仍然存在冲突,您必须显式覆盖默认方法并选择您的类应该选择的方法。

总结 默认方法提供了一种全新的设计对象的方法。

参考 :

Java8 在行动

函数式 Java:Java 8 中的 Lambda 和函数式编程指南

于 2021-01-31T05:02:14.680 回答
0
  1. 默认方法使函数式编程概念成为可能。对于函数式编程类型的代码,我们只需要一个抽象方法。
  2. 此外,在接口中添加方法不会强制所有实现接口的类。简化编码实践
于 2017-07-21T12:07:45.763 回答