何时在 Java 之后使用接口与抽象 class 8

When to use interface vs abstract class after Java 8

我知道这个问题已经被问过很多次了,我们在互联网上到处都是文章,但我仍然不能完全理解,我什么时候应该使用接口或抽象 class 因为我正在使用 Java 15.

大多数文章都在讨论 Java 8 之前的差异和用例,这是有道理的,但当您基本上可以在接口中为您的方法提供主体时就没有意义了。

对我来说唯一有意义的是 non-publicnon-final 限制。

如果有人能指出 1-2 个我需要在 Java 15 中选择接口和抽象 class 的场景示例,我将不胜感激。另外,如果可以是现实生活中的项目,而不是动物或形状 class 个例子。

谢谢!!

default 接口上的方法

显然您指的是 “default methods” 在接口中实现行为的功能。

您应该明白,添加该功能是为了解决这个难题:如何在不破坏实现这些接口的现有 classes 的情况下,在现有接口上追溯添加利用流和 lambda 的功能?

许多新方法已添加到这些接口中,例如在 Java 集合框架中。向现有接口添加方法会自动破坏所有 class 实现接口但缺少新需要的方法。能够提供回退,在现在需要但尚未存在的地方提供一个实现,将解决这个难题。因此,“默认方法”诞生了。

引用上面链接的 Oracle 教程:

Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.

引用 by Brian Goetz、Java Oracle 的语言架构师:

The proximate reason for adding default methods to interfaces was to support interface evolution

因此,这种向界面添加默认行为的功能本身并不意味着成为新的主流功能。 default 的目的不是要替换 abstract

确实,一些经验丰富的 Java 专家建议不要养成在接口上编写默认方法的习惯。他们建议几乎忽略 Java 语言的这个特性。继续将接口视为简单地定义契约,将抽象 classes 视为提供部分实现,以便在子 class.

中完成

您当然可以自由地在您的接口上编写您自己的默认方法。当然,如果您处于发布了其他人可能已经实现的接口的类似情况,并且现在您想要添加方法,那么您当然应该这样做。但是不必要地添加默认方法可能会使其他希望在抽象 class 而不是接口上实现部分实现的程序员感到困惑。

接口上调用default方法的四种情况

在上面的 链接中,Brian Goetz 建议了接口演化之外的其他三种情况,其中接口上的默认方法可能是合适的。这是一个快速提及;有关详细信息,请参阅他的 post。

  • 可选方法 - default 方法抛出一个 UnsupportedOperationException 因为我们期望这个接口的实现更经常不想实现这个方法。
  • 便捷方法
  • 组合器

从界面开始,到共享代码的抽象class

关于接口和抽象之间的选择class:

  • 通常从接口开始。或者,如果您想要各种实现 classes 来混合各种契约,则可以使用多个接口(参见 mixin)。
    • 在添加 default 方法之前请三思。考虑一下您的情况是否符合上述 Brian Goetz 推荐的四种情况之一。
  • 如果您意识到您在多个 class 中有重复的代码,那么请考虑 将该共享代码集中到一个抽象 class 中在 subclasses 中使用。
    • 或者,使用组合而不是继承(在下面讨论)。

例如,您可能有 class 国内 ShippingLabelUS 以及 ShippingLabelCanadaShippingLabelOverseas。这三个都需要在英制磅和公制千克之间进行转换。您发现自己在 class 之间复制该代码。在这一点上,您可能会考虑让所有三个 classes 从抽象 class ShippingLabel 扩展,其中存在权重转换方法的单个副本。

在设计您的 API keep in mind that Java, like most OOP languages, has single-inheritance. So your subclasses are limited to extending only one class. To be a bit more specific about the single-versus-multiple inheritance, I will quote Brian Goetz from this PDF of a slide deck 时:

[regarding default methods on an interface]

Wait,is this multiple inheritance in Java?

• Java always had multiple inheritance of types

• This adds multiple inheritance of behavior

• But not of state, where most of the trouble comes from

组合优于继承

为共享行为使用抽象 class 的替代方法是为特定行为创建单独的 class,然后添加该单独 class 的对象以作为成员保留较大的字段 class。聪明的程序员经常分享这个智慧的明珠:Prefer composition over inheritance.

关于上面的运输标签示例,您可以创建一个 WeightConverter class,其对象将是三个标签 class 中每个标签的成员。在这种安排下,不需要摘要 class.