与Java 8中的默认方法和抽象类的接口
由于Java 8允许在名为Default Methods的接口中默认实现方法,因此在何时使用abstract class之间似乎存在混淆。
那么什么时候应该使用与默认方法的接口,何时应该使用抽象类? 抽象类在这种情况下仍然有用吗?
13个解决方案
229 votes
抽象类比默认方法实现(例如私有状态)要多得多,但是从Java 8开始,无论何时你都可以选择,你应该在界面中使用defender(aka .default)方法。
对默认方法的约束是它只能在对其他接口方法的调用方面实现,而不能引用特定实现的状态。 因此主要用例是更高级别和便捷的方法。
这个新功能的好处在于,在您被迫使用抽象类来实现便捷方法之前,从而将实现者约束为单继承,现在您可以通过接口和最少的实现来实现非常干净的设计 努力强迫程序员。
向Java 8引入default方法的最初动机是希望在不破坏任何现有实现的情况下使用面向lambda的方法扩展Collections Framework接口。 虽然这与公共图书馆的作者更相关,但您可能会发现同样的功能在您的项目中也很有用。 您有一个集中的位置可以添加新的便利,您不必依赖于类型层次结构的其余部分。
Marko Topolnik answered 2019-01-04T02:47:19Z
92 votes
有一些技术差异。 与Java 8接口相比,抽象类仍然可以做得更多:
抽象类可以有一个构造函数。
抽象类更结构化,可以保持状态。
从概念上讲,defender方法的主要目的是在Java 8中引入新功能(如lambda函数)后向后兼容。
Vadym Vasyliev answered 2019-01-04T02:48:04Z
56 votes
本文将对此进行描述。 想想收藏的java.util.List。
List> list = …
list.forEach(…);
forEach不是由java.util.List声明的 java.util.Collection界面。 一个明显的解决方案是 只需将新方法添加到现有界面并提供 在JDK中需要的实现。 但是,一旦发表,它 是不可能在没有破坏的情况下向接口添加方法 现有的实施。
默认方法带来的好处是现在可以实现 添加一个新的默认方法到接口,它不会破坏 实现。
Masudul answered 2019-01-04T02:48:40Z
13 votes
这两者完全不同:
默认方法是在不更改其状态的情况下向现有类添加外部功能。
抽象类是正常的继承类型,它们是旨在扩展的普通类。
Andrey Chaschev answered 2019-01-04T02:49:14Z
12 votes
如本文所述,
Java 8中的抽象类与接口
介绍默认方法后,似乎接口和 抽象类是一样的。 但是,它们仍然是不同的概念 在Java 8中。
抽象类可以定义构造函数。 他们更有条理 可以有一个与他们相关的状态。 相反,默认情况下 方法只能在调用其他方面实现 接口方法,没有引用特定的实现 州。 因此,两者都用于不同目的并在两者之间进行选择 真的取决于场景环境。
Sufiyan Ghori answered 2019-01-04T02:49:56Z
11 votes
关于你的查询
那么什么时候应该使用与默认方法的接口,何时应该使用抽象类? 抽象类在这种情况下仍然有用吗?
java文档提供了完美的答案。
抽象类与接口相比:
抽象类与接口类似。 您无法实例化它们,并且它们可能包含使用或不使用实现声明的混合方法。
但是,使用抽象类,您可以声明非静态和最终的字段,并定义public,protected和private具体方法。
使用接口,所有字段都自动为public,static和final,并且您声明或定义的所有方法(作为默认方法)都是公共的。 此外,您只能扩展一个类,无论它是否是抽象的,而您可以实现任意数量的接口。
以下SE帖子解释了每个用例的用例:
接口和抽象类之间有什么区别?
抽象类在这种情况下仍然有用吗?
是。 它们仍然有用。 它们可以包含非静态的非最终方法和属性(除了public之外的受保护,私有),即使使用Java-8接口也是如此。
Ravindra babu answered 2019-01-04T02:51:33Z
10 votes
每当我们在抽象类和接口之间做出选择时,我们总是(几乎)更喜欢默认(也称为防御者或虚拟扩展)方法。
默认方法已经结束了经典的接口模式和一个实现该接口中大部分或全部方法的伴随类。 一个例子是Ball.现在我们应该在接口本身中实现这些方法以提供默认功能。 实现接口的类可以选择覆盖方法或继承默认实现。
默认方法的另一个重要用途是Ball.假设我有一个Ball类:
Ball
现在在Java 8中引入了一个新的特性流。 我们可以通过使用Ball方法添加到接口来获取流。 如果stream不是默认方法,则Ball接口的所有实现都将被破坏,因为它们不会实现此新方法。 向接口添加非默认方法不是AbstractMethodError。
但是假设我们不重新编译该类并使用包含此类Ball的旧jar文件。该类将在没有此方法的情况下正常加载,可以创建实例并且似乎一切正常。 但如果程序在Ball的实例上调用stream方法,我们将获得AbstractMethodError.因此,制作方法默认解决了这两个问题。
i_am_zero answered 2019-01-04T02:52:29Z
6 votes
Java接口中的默认方法支持接口演进。
给定现有接口,如果您希望在不破坏与旧版本接口的二进制兼容性的情况下向其添加方法,则可以使用两个选项:添加默认方法或静态方法。 实际上,添加到接口的任何抽象方法都必须由实现此接口的类或接口实现。
静态方法对于类是唯一的。 默认方法对于类的实例是唯一的。
如果向现有接口添加默认方法,则实现此接口的类和接口不需要实现它。 他们能
实现默认方法,它会覆盖已实现接口中的实现。
重新声明使其成为抽象的方法(没有实现)。
什么都不做(然后简单地继承了实现接口的默认方法)。
有关此主题的更多信息。
octoback answered 2019-01-04T02:53:37Z
4 votes
为什么我们必须使用抽象类:
抽象类可以有抽象和非抽象的方法。
抽象类不支持多重继承。
抽象类可以包含final,non-final,static和non-static变量。
抽象类可以有静态方法,主方法和构造函数。
抽象类可以提供接口的实现。
abstract关键字用于声明抽象类。
为什么我们必须使用接口:
界面是您的应用程序设计中最抽象的级别
接口支持多重继承。
仅为描述子类的签名而创建的接口
接口只有静态和最终变量。
使用default方法只是为了扩展某些接口,例如外部lib。 但大多数情况下这不是很好的做法:)
Dmytro Melnychuk answered 2019-01-04T02:55:14Z
4 votes
Remi Forax规则是您不使用抽象类进行设计。 您可以使用界面设计应用程序。 Watever是Java的版本,无论语言是什么。 它受到SOLID原则中的接口隔离原则的支持。
您可以稍后使用Abstract类来分解代码。 现在使用Java 8,您可以直接在界面中完成。 这是一个设施,而不是更多。
Nicolas Zozol answered 2019-01-04T02:55:42Z
1 votes
什么时候应该使用默认方法的接口,什么时候应该使用 使用抽象类?
向后兼容性:想象一下,你的界面是由数百个类实现的,修改该界面会强制所有用户实现新添加的方法,即使它对于实现你的界面的许多其他类来说也不是必不可少的,而且它允许你的界面是一个 功能界面
事实&限制:
1 - 5月只能在界面内声明,而不是在类或抽象类。
2 - 必须提供一个身体
3 - 不假设它是抽象的,因为接口中使用的其他常规方法。
Ahmad Sanie answered 2019-01-04T02:56:37Z
1 votes
Java接口中的默认方法更多地用于提供函数的虚拟实现,从而节省了该接口的任何实现类,即使它们只想处理一个抽象方法,也不需要声明所有抽象方法。因此,接口中的默认方法更多地取代了适配器类的概念。
但是,抽象类中的方法应该提供一个有意义的实现,任何子类只有在需要覆盖常用功能时才应该覆盖。
shubh answered 2019-01-04T02:57:06Z
0 votes
请首先考虑开放/封闭原则。 接口中的默认方法DO VIOLATE它。 这是Java中的一个不好的功能。 它鼓励糟糕的设计,糟糕的架构,低软件质量。 我建议完全避免使用默认方法。
问自己几个问题:你为什么不把你的方法放到抽象类? 那你需要多个抽象类吗? 然后想想你的班级负责什么。 你确定你要把单一课程的所有方法真正实现同样的目的吗? 可能你会区分几个目的,然后将你的班级分成几个班级,每个目的都是自己的班级。
mentallurg answered 2019-01-04T02:57:36Z