Java是否计划default method
替代Abstract Class
?
我找不到真正的案例来使用默认方法而不是抽象?
答案 0 :(得分:8)
没有这样的计划,你可以从比较已经记录的意图中得出这些计划,这些意图与这样一个计划的含义不同:
主要目标是允许接口演化,即添加新方法。如果将新方法添加到接口,则实现该接口的现有类将缺少实现,这将是不兼容的。为了兼容,实现必须来自某个地方,因此它是由默认方法提供的。
...
Java接口的主要目的是specify a contract,任何类都可以实现,而不必改变它在类层次结构中的位置。确实,在Java 8之前,接口纯粹是抽象的。但是,这不是接口的基本属性。即使包含默认方法,其核心接口仍然在实现类上指定合同。实现类可以覆盖默认方法,因此该类仍然可以完全控制其实现。 (另请注意default methods cannot be final。)
向接口添加默认方法的近因是支持接口演进,...
以下是一些完全符合设计目标的用例:
界面演变。在这里,我们向现有接口添加一个新方法,该接口在该接口上的现有方法方面具有合理的默认实现。一个示例是将
forEach
方法添加到Collection
,其中默认实现是根据iterator()
方法编写的。“可选”方法。在这里,接口的设计者说“如果他们愿意接受需要的功能限制,那么实现者就不需要实现这种方法”。例如,
Iterator.remove
被赋予默认值UnsupportedOperationException
;因为绝大多数Iterator
的实现都有这种行为,所以默认情况下这个方法基本上是可选的。 (如果来自AbstractCollection
的行为在Collection
上表示为默认值,我们可能会对变异方法执行相同操作。)便利方法。这些方法严格来说是为了方便,通常也是根据类中的非默认方法实现的。第一个示例中的
logger()
方法是对此的合理说明。组合子。这些是基于当前实例实例化接口的新实例的组合方法。例如,方法
Predicate.and()
或Comparator.thenComparing()
是组合子的示例。
请注意,这些不是针对抽象类的主域,例如提供框架实现。除了technical differences之外,抽象类在语义上是不同的,因为它们承担了关于如何实现功能的设计决策,即使使用default
方法,这些接口也不应该。例如。一个众所周知的例子是List
接口,其中存在两个根本不同的抽象类,AbstractList
和AbstractSequentialList
以及子类的选择或实现List
完全不同的应该不被界面排除在外。因此List
接口定义了契约,并且永远不能替代提供特定基本实现的抽象类。
答案 1 :(得分:6)
其他答案以及其他材料的链接已经充分涵盖了接口和抽象类之间的技术差异。没有完全覆盖的是为什么要使用其中一个。
考虑在Java中使用类或接口的两种不同方式:作为调用者或作为子类。调用者具有对象引用,可以调用public
方法并通过该引用访问public
字段。子类也可以访问,调用和覆盖超类的protected
成员。类可以有protected
个成员,但接口不能。
一个常见的问题似乎是,既然我们有默认方法,为什么我们需要抽象类?默认方法是界面向呼叫者提供的内容的一部分。类的protected
方法不适用于调用者;它只适用于子类。因此,如果要与子类共享实现,则使用类(或抽象类)并定义protected
成员和字段。
protected
机制允许类与子类通信,这与它与调用者的通信方式不同。
但是OP提出了相反的问题:为什么人们会优先使用默认方法来抽象类?在您实际可以选择的情况下(即,您的抽象不需要状态或受保护的方法,或抽象类具有的接口不具有的任何东西),具有默认方法的接口远比抽象类更少约束。你只能从一个类继承;你可以从许多接口继承。因此,具有默认方法的接口可以像无状态特征或mixin一样,允许您从多个接口继承行为。
鉴于接口和抽象类用于不同的目的,没有计划删除或替换任何东西。
答案 2 :(得分:5)
引入接口中的默认方法的一个原因是允许向JDK接口添加新方法。
使用特定版本的接口编译类后,如果没有此功能,则无法向此接口添加新方法。使用接口中的默认方法,可以更改功能接口。
答案 3 :(得分:5)