与Java 8中的默认方法和抽象类的接口

Nar*_*hai 489 java abstract-class interface java-8 default-method

由于Java 8允许在名为Default Methods的接口中默认实现方法,因此在何时使用a之间似乎存在混淆abstract class.

那么什么时候应该使用与默认方法的接口,何时应该使用抽象类?抽象类在这种情况下仍然有用吗?

Mar*_*nik 282

抽象类比默认方法实现(例如私有状态)要多得多,但是从Java 8开始,无论何时你都可以选择,你应该default在界面中使用defender(aka.)方法.

对默认方法的约束是它只能在对其他接口方法的调用方面实现,而不引用特定实现的状态.所以主要用例是更高层次和更方便的方法.

这个新功能的好处在于,在您被迫使用抽象类来实现便捷方法之前,从而将实现者约束为单继承,现在您可以只使用接口和最少的实现来实现真正干净的设计努力强迫程序员.

default向Java 8 引入方法的最初动机是希望在不破坏任何现有实现的情况下使用面向lambda的方法扩展Collections Framework接口.虽然这与公共图书馆的作者更相关,但您可能会发现同样的功能在您的项目中也很有用.您有一个集中的位置可以添加新的便利,您不必依赖于类型层次结构的其余部分.

  • 通过这种推理,他们将添加的下一件事是默认方法声明.我仍然不确定这个,这个功能看起来更像是一个黑客,我被暴露给每个人滥用. (31认同)
  • @Anuroop不仅仅是默认 - 这是唯一的选择.接口不能声明实例状态,这就是为什么抽象类仍然存在的原因. (6认同)
  • Marko Topolnik,你的答案是死的。但我想建议更新您的答案。您可能想补充一点,默认方法的美妙之处在于,如果接口添加了新的默认方法,您之前对该接口的实现不会中断。在 Java 8 之前,情况并非如此。 (4认同)
  • 我可以看到Java 8时代Abstract Classes的唯一用途是用于定义非最终字段。默认情况下,在“接口”中,这些字段为最终字段,因此一旦分配它们便无法更改它们。 (2认同)
  • @PhilipRego抽象方法不会调用任何东西,因为它们没有实现.类中实现的方法可以访问类的状态(实例变量).接口无法声明它们,因此默认方法无法访问它们.他们必须依赖于提供访问状态的实现方法的类. (2认同)

小智 112

有一些技术差异.与Java 8接口相比,抽象类仍然可以做更多的事情:

  1. 抽象类可以有一个构造函数.
  2. 抽象类更结构化,可以保持状态.

从概念上讲,defender方法的主要目的是在Java 8中引入新功能(如lambda函数)后向后兼容.

  • 这个答案实际上是正确的,特别是"从概念上讲,后卫方法的主要目的是向后兼容" (16认同)
  • 关于点号的更微妙的一点.2以上关于"可以保持状态是这个".抽象类可以保存可以在以后更改的状态.接口也可以保持状态,但是一旦在实例创建后分配了状态,就不能改变状态. (3认同)
  • @Anuroop我不会将接口的“ public static final”字段描述为“ state”。“静态”部分意味着“静态”根本与特定实例无关。它们被分配了_on类实例化_,与_after实例创建_不同。 (2认同)
  • 我喜欢这个答案,但是“从概念上讲,防御者方法的主要目的是在 Java 8 中引入新功能(如 lambda 函数)后的向后兼容性”是什么意思? (2认同)

Mas*_*dul 62

这是这所描述的文章.想想forEach收藏品.

List<?> list = …
list.forEach(…);
Run Code Online (Sandbox Code Playgroud)

在foreach不声明java.util.List也不 java.util.Collection界面中.一个显而易见的解决方案是将新方法添加到现有接口,并在JDK中提供所需的实现.但是,一旦发布,就不可能在不破坏现有实现的情况下向接口添加方法.

默认方法带来的好处是,现在可以向接口添加新的默认方法,并且不会破坏实现.

  • @AndreyChaschev如果向接口添加新方法,则所有实现者都必须实现该新方法.因此它破坏了现有的实现. (25认同)
  • @MarkoTopolnik谢谢,错过了.只是提到有一种方法可以*部分*避免这种情况 - 通过在默认的抽象实现中提供此方法.对于这个例子,这将是`AbstractList :: forEach`抛出`UnsupportedOperationException`. (4认同)
  • @AndreyChaschev是的,这是旧的方式(khm ...*是当前的方式*:),缺点是它将实现者限制为从提供的抽象实现单继承. (3认同)

Suf*_*ori 17

正如在描述这个文章,

Java 8中的抽象类与接口

在引入Default Method之后,接口和抽象类似乎是相同的.但是,它们在Java 8中仍然是不同的概念.

抽象类可以定义构造函数.它们更结构化,并且可以具有与它们相关联的状态.相反,默认方法只能在调用其他接口方法的条件下实现,而不能引用特定实现的状态.因此,用于不同目的和在两者之间进行选择实际上取决于场景上下文.


And*_*hev 16

这两个是完全不同的:

默认方法是在不更改其状态的情况下向现有类添加外部功能.

抽象类是常规类型的继承,它们是旨在扩展的普通类.


Uma*_*hir 16

虽然它是一个老问题,但也让我对此提出意见。

  1. 抽象类:在抽象类中,我们可以声明子类所需的实例变量

    接口:在接口内部,每个变量都是 public static 和 final 我们不能声明实例变量

  2. 抽象类:抽象类可以谈论对象的状态

    接口:接口永远不能谈论对象的状态

  3. 抽象类:在抽象类中,我们可以声明构造函数

    接口:在接口内部我们不能声明构造函数,因为构造函数的目的
    是初始化实例变量。那么如果我们不能在 interfaces 中有实例变量,那么构造函数有什么需要呢

  4. 抽象类:在抽象类中,我们可以声明实例块和静态块

    接口:接口不能有实例块和静态块。

  5. 抽象类:抽象类不能引用 lambda 表达式

    接口:具有单一抽象方法的接口可以引用 lambda 表达式

  6. 抽象类:在抽象类中,我们可以覆盖 OBJECT CLASS 方法

    接口:我们不能覆盖接口内的 OBJECT CLASS 方法。

我将在结束时指出:

接口中的默认方法概念/静态方法概念只是为了保存实现类,而不是提供有意义的有用实现。默认方法/静态方法是一种虚拟实现,“如果你想你可以使用它们,或者你可以在实现类中覆盖它们(在默认方法的情况下)”这样,每当接口中有新方法时,我们就不必在实现类中实现新方法添加。因此接口永远不能等同于抽象类。


i_a*_*ero 13

每当我们在抽象类和接口之间做出选择时,我们总是(几乎)更喜欢默认(也称为防御者或虚拟扩展)方法.

  1. 默认方法已经结束了经典的接口模式和一个实现该接口中大部分或全部方法的伴随类.一个例子是Collection and AbstractCollection.现在我们应该在接口本身中实现方法以提供默认功能.实现接口的类可以选择覆盖方法或继承默认实现.
  2. 默认方法的另一个重要用途是interface evolution.假设我有一个Ball类:

    public class Ball implements Collection { ... }

现在在Java 8中引入了一个新的特性流.我们可以通过使用stream添加到接口的方法来获取流.如果stream不是默认方法,那么Collection接口的所有实现都会破坏,因为它们不会实现这个新方法.向接口添加非默认方法不是source-compatible.

但是假设我们不重新编译该类并使用包含此类的旧jar文件Ball.如果没有这个缺少的方法,该类将加载正常,可以创建实例,似乎一切正常.但是如果程序调用我们将获得的stream实例上的方法.所以制作方法默认解决了这两个问题.BallAbstractMethodError


Rav*_*abu 13

关于你的查询

那么什么时候应该使用与默认方法的接口,何时应该使用抽象类?抽象类在这种情况下仍然有用吗?

java 文档提供了完美的答案.

抽象类与接口相比:

抽象类与接口类似.您无法实例化它们,并且它们可能包含使用或不使用实现声明的混合方法.

但是,对于抽象类,您可以声明非静态和最终的字段,并定义public,protected和private具体方法.

使用接口,所有字段都自动为public,static和final,并且您声明或定义的所有方法(作为默认方法)都是公共的.此外,您只能扩展一个类,无论它是否是抽象的,而您可以实现任意数量的接口.

以下SE帖子解释了每个用例的用例:

接口和抽象类之间有什么区别?

抽象类在这种情况下仍然有用吗?

是.它们仍然有用.它们可以包含非静态的非final方法 和属性(除了public之外还有protected,private),即使使用Java-8接口也是如此.


kir*_*off 9

Java接口中的默认方法支持接口演进.

给定现有接口,如果您希望在不破坏与旧版本接口的二进制兼容性的情况下向其添加方法,则可以使用两个选项:添加默认方法或静态方法.实际上,添加到接口的任何抽象方法都必须由实现此接口的类或接口实现.

静态方法对于类是唯一的.默认方法对于类的实例是唯一的.

如果向现有接口添加默认方法,则实现此接口的类和接口不需要实现它.他们能

  • 实现默认方法,它会覆盖已实现接口中的实现.
  • 重新声明使其成为抽象的方法(没有实现).
  • 什么也不做(然后简单地继承了实现接口的默认方法).

有关此主题的更多信息.


Nic*_*zol 5

Remi Forax的规则是您不使用Abstract类进行设计。您可以使用interfaces设计应用程序。无论语言是什么,Watever都是Java的版本。它是由支持覆盖整个院落隔离原则SOL d的原则。

您以后可以使用Abstract类来分解代码。现在,使用Java 8,您可以直接在界面中进行操作。这是一个设施,仅此而已。


归档时间:

查看次数:

104455 次

最近记录:

5 年,11 月 前