Inheritance Java8——默认方法与抽象类的接口

Inheritance Java8——默认方法与抽象类的接口,inheritance,interface,abstract-class,java-8,Inheritance,Interface,Abstract Class,Java 8,我正试图找到一个完整的答案: “为什么/何时使用抽象类而不是接口。” 并寻求以下方面的验证/建议 答案是, “为其中一些提供实现。在具体类之前 进来定义特定类型,一个抽象类,通常就在下面 继承层次结构中的接口(如JavaAPI中的许多示例) 实现并固定接口定义的结构的一些常见方面 使用抽象类的另一个很好的原因是类型之间有一个清晰的逻辑层次结构。 抽象类用于组织该层次结构 通过作为抽象类而不是具体类,强制只在具体类上实例化对象 在这个层次结构中,它们是完全定义的,因此是有意义的。” 然后,在这种情

我正试图找到一个完整的答案:

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

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

答案是,

“为其中一些提供实现。在具体类之前 进来定义特定类型,一个抽象类,通常就在下面 继承层次结构中的接口(如JavaAPI中的许多示例) 实现并固定接口定义的结构的一些常见方面

使用抽象类的另一个很好的原因是类型之间有一个清晰的逻辑层次结构。 抽象类用于组织该层次结构 通过作为抽象类而不是具体类,强制只在具体类上实例化对象 在这个层次结构中,它们是完全定义的,因此是有意义的。”

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

“自Java 8以来,接口可以定义实现。 为什么我不在接口中编写默认方法而不是实现这些方法的抽象类? "

答案是:

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

另一种是:子类可以通过super调用抽象类方法,而默认接口方法不能调用抽象类方法。此外,接口没有可由子类调用的构造函数

其余的原因与上面Java8之前版本中的原因相同。 "

除了上面提到的这些,为什么我更喜欢抽象类而不是接口,尤其是现在我有了自Java8以来的默认接口方法

请注意:我已经看到了和其他一些有用的讨论。这个问题相当于为什么选择抽象类而不是接口

蒂亚

简短回答:

  • 一个类可以只扩展一个类
  • 一个类可以实现任意数量的接口

  • 具有默认方法的接口只能定义行为,而抽象类可以具有状态

    换句话说,如果有一个成员变量需要在子类层次结构中共享,则应该使用抽象类(这里的共享意味着子类可以直接访问它,如果它不是私有的,也可以通过方法访问)


    抽象类的另一个用例是,如果您想要覆盖一些
    对象
    方法,例如
    equals
    toString
    。这不能通过默认方法来完成。

    以下是选择抽象类而不是接口的一些原因。您列出的字段-私有字段等是一些主要字段。这些是一些更微妙的问题

    • 字体清晰。您只能扩展一个类。这使它更清楚你的对象是什么以及如何使用它
    • 钻石问题。您必须在接口中实现所有默认方法,以帮助避免菱形问题。如果接口是集合,这可能是一个巨大的痛苦,因为有十亿个集合。对于抽象类,您只需要覆盖需要覆盖的内容
    • 在Java8中,存在lambda表达式,使用要实现的方法传递接口的旧例程已被篡夺。不过,当您看到一个带有默认方法的接口时,这可能会以您可能不希望的方式进行解释
    以下是甲骨文对此问题的看法:

    您应该使用哪一种,抽象类还是接口? 如果这些语句适用于抽象类,请考虑使用 你的情况:

    • 您希望在几个密切相关的类之间共享代码
    • 您希望扩展抽象类的类具有许多公共方法或字段,或者需要访问修饰符而不是 公共的(例如受保护的和私有的)
    • 您想要声明非静态或非最终字段。这使您能够定义可以访问和修改状态的方法 它们所属的对象
    在本文中,Orace为这两种类型系统之间的区别辩护

    编辑以澄清“钻石问题”要点 这里(以及许多其他地方)描述了问题

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

    现在的解决策略有点复杂,但这里有一个很好的描述: (来自)

    为了解决钻石问题,有一个优先顺序 仅当类实现所有默认值时才使用实现/ 其接口的可选方法,可以编译代码和 使用这个类的实现。否则编译器将尝试 使用接口的默认值修补缺少的实现 实施如果有多个默认的 方法,则出现菱形问题,编译器拒绝 汇编如果类实现了接口的默认 方法,则将使用该类的实现,而不是 接口的默认实现

    如果您坚持使用抽象类,就永远不会遇到这个问题。但是,如果您的对象需要实现两个接口(因为它需要添加到需要这些类型的列表中,例如,这些接口具有冲突的方法签名,那么您将不得不重新定义一整套方法,即使这意味着您只是在进行超级校准