当前位置: 首页 > 知识库问答 >
问题:

Java8-使用默认方法的接口与抽象类

哈栋
2023-03-14

我试图给出一个完整的答案:

"为什么/何时使用抽象类而不是接口。"

并寻找以下方面的验证/建议。

对此的一个答案是,

在具体类来定义特定类型之前,抽象类通常位于继承层次结构中接口的正下方(就像Java API中的许多示例一样),实现并固定接口定义的结构的一些公共方面。

使用抽象类的另一个很好的理由是类型之间有一个清晰的逻辑层次结构。抽象类具有组织层次结构的作用,同时通过作为抽象类而不是具体类,迫使对象只在该层次结构下面的具体类上实例化,在这些具体类中,对象被完全定义,因此是有意义的。“

然后,在这种情况下,出现了问:

“自从Java8以来,接口可以定义默认方法实现。为什么我不在接口中编写默认方法,而不是在实现那些方法的抽象类中编写呢?”

对此的答案是:

“一个原因是:接口方法都是公共的,字段成员都是常量(final&public)。您可能需要限制方法的访问权限和/或使它们在非常量状态下操作。

另一个是:后代类可以通过super调用抽象类方法,而它不能在默认接口方法上这样做。此外,接口没有可由后代调用的构造函数

其余的原因与上面的pre-Java8中的相同。“

除了上面的这些,为什么我宁愿选择抽象类而不是接口,特别是现在我已经有了Java8以来的默认接口方法?

请注意:我已经看到了Java8中的默认方法与抽象类中的非抽象方法,以及Java8中的默认方法与抽象类的接口,还有一些其他有用的讨论。这是关于为什么选择抽象类而不是接口的问题。

共有1个答案

席弘图
2023-03-14

以下是选择抽象类而不是接口的一些原因。您列出的那些--私有字段等,是一些主要的字段。这是几个比较微妙的

  • 类型清晰度。只能扩展一个类。这使得您的对象是什么以及如何使用它变得更加清晰。
  • 钻石问题。您必须在一个接口中实现所有默认方法,以帮助避免菱形问题。如果接口是集合,这可能是一个巨大的痛苦,因为有十亿个集合。对于抽象类,您只需覆盖您需要的内容
  • 在Java8中,有lambda表达式,在一个接口上传递一个要实现的方法的老例程已经被篡夺了。不过,当您看到具有默认方法的接口时,可以以您可能不希望的方式对其进行解释

以下是甲骨文对这个问题的看法:

    null

在本文中,Orace维护了两种类型系统https://docs.oracle.com/javase/tutorial/java/iandi/abstract.html之间的区别

编辑以澄清“Diamond problem”bullet此处(和其他许多地方)对问题进行了描述http://www.lambdafaq.org/what-about-the-Diamond-problem/

当您从声明相同方法的两个地方继承,并且在解析函数调用时必须选择一个时,就会出现问题。这在Java7中从来不是问题,因为您只能扩展一个类,接口没有方法。

现在的解决策略有点复杂,但这里有一个很好的描述:(摘自http://blog.loxal.net/2013/05/java-8-default-interface.html)

为了解决菱形问题,使用实现的顺序有一个优先级:只有当类实现了其接口的所有默认/可选方法时,才能编译代码并使用该类的实现。否则,编译器将尝试用接口的默认实现修补缺少的实现。并且如果一个方法有多个默认实现,那么就会出现菱形问题,编译器会拒绝编译。此外,如果类实现了接口的默认方法,则将使用类的实现而不是接口的默认实现。

如果坚持使用抽象类,就永远不会遇到这个问题。但是,如果您的对象需要实现两个接口(因为它需要被添加到期望这些类型的列表中,例如),并且这些接口具有冲突的方法签名,那么您将不得不重新定义一大堆方法,即使这意味着您只是在进行超级调用,这在某种程度上违背了基于继承的动态调度的观点。它不是一个破坏交易的因素,而是在构造复杂的Java项目时需要考虑的问题

 类似资料:
  • 我想给出一个完整的答案: “为什么/何时使用抽象类而不是接口。” 并寻求对以下方面的验证/建议。 “一个原因是:接口方法都是公共的,字段成员都是常量(final和public)。您可能需要限制方法的访问权限和/或使它们在非常量状态下操作。 另一个是:子代类可以通过super调用抽象类方法,而它不能对默认接口方法调用抽象类方法。此外,接口没有可由后代调用的构造函数。 其余的原因与上面的pre-Jav

  • 问题内容: Java 8接口默认方法与抽象类中的非抽象方法-两者之间是否有任何区别(除了iface-类,可见性等不同) 默认方法不是Java的后退一步,是否违反Java多年来宣传的本质? 问题答案: 如果抽象子类的具体子类被super()覆盖,则抽象类中的非抽象方法将被调用。因此,存在多种可能性。如果不重写method,则将执行超类方法。如果我们在具体的子类方法中使用super(),则将执行被超类

  • Java 8接口默认方法与抽象类中的非抽象方法--两者之间有什么区别吗(除了iface-class、可见性等的区别之外) 默认方法是不是在Java中倒退了一步,意味着它违背了Java多年来宣传的本质?!

  • 为什么上面的代码有编译错误“java:default method equals in interface Table重写java.lang.Object的一个成员”?难道我们不能使用接口默认方法重写hashCode和equals方法吗?假设我在同一个接口中有方法来确定实现这个接口的对象的相等性?

  • 抽象方法和默认方法有什么区别? 在从“贵族”那里知道答案之前,我认为默认方法不同于defender方法,默认方法只不过是接口内部的抽象方法(没有关键字abstract)。这两个错误的观念导致这个愚蠢的问题被提出来。我从来不想问一个已经“问得很好,回答得很好”的问题来麻烦大家。 我想删除这个问题,但我没有,因为两个原因-1。stackoverflow阻止了我,2。贵族的回答是出神入化的。

  • 主要内容:1 Java8 默认方法的介绍,2 Java8 默认方法的案例1 Java8 默认方法的介绍 Java提供了一种在接口内部创建默认方法的功能。在接口内部定义并带有默认标记的方法称为默认方法。这些方法是非抽象方法。 2 Java8 默认方法的案例 在下面的示例中,Sayable是一个功能接口,其中包含默认值和抽象方法。默认方法的概念用于定义具有默认实现的方法。您还可以覆盖默认方法,以为该方法提供更具体的实现。 输出结果为: