我试图想出一个完整的答案:
" 为什么/何时使用抽象类而不是接口。"
并在以下方面寻找验证/建议。
答案是,
"为其中一些提供实施。在具体课程之前 进来定义特定类型,一个抽象类,通常在下面 继承层次结构中的接口(与Java API中的许多示例一样) 实现并确定了接口定义的结构的一些常见方面。
使用抽象类的另一个好理由是类型之间存在明确的逻辑层次结构。 抽象类可用于组织该层次结构 通过作为一个抽象类而不是一个具体的强制,强制对象只在具体类上实例化 在这个层次结构的下方,它们是完全定义的,因此是有意义的。"
然后,在这种情况下,Q:
"自Java 8以来,接口可以定义default method实现。 为什么我不会在接口中编写默认方法而不是实现这些方法的抽象类? "
答案是:
" 一个原因是:接口方法都是公共的,字段成员都是常量(final和amp; public)。 您可能希望限制方法的访问权限和/或使它们在非常量状态下运行。
另一个是:后代类可以通过super调用抽象类方法,而在默认接口方法上则不能这样做。此外,接口没有后代调用的构造函数。
其余原因与上面的Java 8之前的原因相同。 "
除了上面这些之外,为什么我宁愿选择一个抽象类而不是一个接口,特别是现在我有了自Java 8以来的默认接口方法?
请注意:我已经看过Java 8 default methods vs. non-abstract methods in abstract classes和Interface with default methods vs Abstract class in Java 8以及其他一些有用的讨论。这个Q更像是为什么选择一个接口的抽象类而不是相反。
TIA。
答案 0 :(得分:7)
使用默认方法的接口只能定义行为,而抽象类可以具有状态。
换句话说,如果存在需要在子类层次结构中共享的成员变量,则应使用抽象类(这里的共享意味着如果子类不是私有的或通过方法,则子类可以直接访问它。) / p>
抽象类的另一个用例是,如果要覆盖某些Object
方法,例如equals
或toString
。这不能通过默认方法完成。
答案 1 :(得分:7)
以下是在界面上选择抽象类的一些原因。你列出的那些 - 私人领域等,是一些主要的领域。这些是一些更微妙的
以下是甲骨文在这个问题上所说的话:
您应该使用哪些,抽象类或接口? 如果任何这些语句适用,请考虑使用抽象类 你的情况:
- 您希望在几个密切相关的类之间共享代码。
- 您希望扩展抽象类的类具有许多常用方法或字段,或者需要除了之外的访问修饰符 公共(如受保护和私人)。
- 您想要声明非静态或非最终字段。这使您可以定义可以访问和修改状态的方法 他们所属的对象。
在本文中,Orace捍卫了两种类型系统之间的区别 https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html
编辑澄清"钻石问题"子弹 这里描述的问题(以及许多其他地方) http://www.lambdafaq.org/what-about-the-diamond-problem/
当您从声明相同方法的两个地方继承时,会出现问题,并且在解析函数调用时必须选择一个。这在Java 7中从来都不是问题,因为你只能扩展一个类而接口没有方法。
分辨率策略现在有点复杂,但这里有一个很好的描述: (来自http://blog.loxal.net/2013/05/java-8-default-interface.html)
为了解决钻石问题,优先顺序为a 使用实现:仅当类实现所有默认值/ 其接口的可选方法,代码可以编译和 使用此类的实现。否则编译器会尝试 使用接口的默认值修补缺少的实现 实现。如果有多个默认实现 方法,然后发生钻石问题,编译器拒绝 汇编。此外,如果该类实现了接口的默认值 方法,将使用该类的实现来代替 接口的默认实现。
如果你坚持抽象类,你将永远不会遇到这个问题。但是,如果您的对象需要实现两个接口(因为它需要添加到期望这些类型的列表中,例如),和这些接口具有冲突的方法签名,您将不得不重新定义了一大堆方法,即使这意味着你只是在进行超级调用,这种方式会破坏基于继承的动态调度。它不是一个交易破坏者,但在构建复杂的Java项目时需要考虑的事项
答案 2 :(得分:1)
简短回答:
答案 3 :(得分:0)
Abstract类与普通类共享更多相似之处,而interface表示没有内部状态的类公共API。
抽象类只能从一个类继承,并且可以实现接口,但接口只能扩展多个接口。
抽象类属性也可以是瞬态/易变的
抽象类方法也可以是final / static / synchronized / native
接口方法也可以是默认或静态的实现。(不能同时是默认和静态。)