在Java 8中与默认方法与抽象类的接口

由于Java 8允许在名为Default Method的接口中默认实现方法 ,所以在我将何时使用abstract class之间似乎存在混淆。

那么何时应该使用默认方法的接口,何时应该使用抽象类呢? 抽象类在这种情况下仍然有用吗?

抽象类比默认的方法实现(比如私有状态)要多得多,但是从Java 8开始,只要你有select,你应该在界面中使用defender(aka.default)方法。

对默认方法的约束是,它只能以对其他接口方法的调用来实现,而不涉及特定实现的状态。 所以主要的用例是更高级的和方便的方法。

关于这个新function的好处是,在你被强迫使用抽象类作为便利方法之前,因此将实现者约束为单一的inheritance,现在你可以拥有一个非常干净的devise,只有接口和最less的实现程序员强加于自己的努力。

有一些技术上的差异。 与Java 8接口相比,抽象类仍然可以做得更多:

  1. 抽象类可以有一个构造函数。
  2. 抽象类更结构化,可以保持一个状态。

从概念上来说,defender方法的主要目的是在Java 8中引入新特性(如lambda函数)后向后兼容。

这正在这篇文章中描述。 考虑forEach集合。

 List<?> list = … list.forEach(…); 

forEach没有被java.util.Listjava.util.Collection接口声明。 一个明显的解决scheme是将新方法添加到现有的接口中,并在JDK中提供所需的实现。 但是,一旦发布,就不可能在不破坏现有实现的情况下向接口添加方法。

默认方法带来的好处是,现在可以向接口添加一个新的默认方法,并且不会中断实现。

这两个是完全不同的:

默认方法是将外部function添加到现有的类而不改变它们的状态。

而抽象类是一种正常的inheritancetypes,它们是普通的类 ,有待扩展。

每当我们在抽象类和接口之间进行select的时候,我们都应该(几乎)倾向于默认(也称为防御者或虚拟扩展)方法。

  1. 默认方法已经结束了经典的接口模式和一个实现该接口中大部分或全部方法的伴随类。 Collection and AbstractCollection就是一个例子。 现在我们应该在接口中实现这些方法来提供默认function。 实现接口的类可以select覆盖方法或inheritance默认实现。
  2. 默认方法的另一个重要用途是interface evolution 。 假设我有一个类Ball:

    public class Ball implements Collection { ... }

现在在Java 8中引入了一个新的特性stream。 我们可以通过使用添加到接口的stream方法来获得一个stream。 如果stream不是默认方法,那么Collection接口的所有实现都会被破坏,因为它们不会实现这个新的方法。 向接口添加非默认方法不是source-compatible

但是,假设我们不重新编译这个类并使用一个包含这个类的旧的jar文件。 该类将加载罚款没有这个缺less的方法,可以创build实例,似乎一切工作正常。 但是如果程序在Ball实例上调用stream方法,我们将得到AbstractMethodError 。 所以制作方法默认解决了这两个问题。

关于你的查询

那么何时应该使用默认方法的接口,何时应该使用抽象类呢? 抽象类在这种情况下仍然有用吗?

java 文档提供了完美的答案。

抽象类与接口相比:

抽象类与接口类似。 你不能实例化它们,它们可能包含一个声明有或没有实现的混合方法。

但是,对于抽象类,您可以声明非静态和最终的字段,并定义公共,受保护和私有的具体方法。

使用接口,所有的字段都是自动公开的,静态的和最终的,你声明或定义的所有方法(作为默认方法)是公共的。 另外,只能扩展一个类,不pipe它是否抽象,而可以实现任意数量的接口。

下面的SE文章解释了每个用例的用例:

界面和抽象类有什么区别?

抽象类在这种情况下仍然有用吗?

是。 他们仍然有用。 它们可以包含非静态的,非最终的方法和属性( 保护,公共之外是私有的 ),即使使用Java-8接口也是不可能的。

如本文所述,

Java 8中的抽象类与接口

引入了Default Method之后,接口和抽象类似乎是一样的。 但是,在Java 8中它们仍然是不同的概念。

抽象类可以定义构造函数。 他们更有条理,可以有一个与他们有关的国家。 而相比之下,默认方法只能在调用其他接口方法的情况下实现,而不涉及特定实现的状态。 因此,两者用于不同的目的和两者之间的select实际上取决于场景的情况。

Java接口中的默认方法可以使接口发展

给定一个现有的接口,如果你想添加一个方法而不破坏老版本的接口的二进制兼容性,你可以有两个select:添加一个默认或静态方法。 实际上,任何添加到接口的抽象方法都必须由实现这个接口的类或接口来实现。

静态方法对于一个类是唯一的。 默认方法对于类的实例是唯一的。

如果将默认方法添加到现有接口,则实现此接口的类和接口不需要实现它。 他们能

  • 实现默认的方法,并覆盖实现的接口中的实现。
  • 重申声明的方法(没有实现),这使得它是抽象的。
  • 什么都不做(然后从实现的接口的默认方法是简单的inheritance)。

更多关于这个话题。

为什么我们必须使用抽象类:

  1. 抽象类可以有抽象和非抽象的方法。
  2. 抽象类不支持多重inheritance。
  3. 抽象类可以有最终的,非最终的,静态的和非静态的variables。
  4. 抽象类可以有静态方法,主要方法和构造方法。
  5. 抽象类可以提供接口的实现。
  6. abstract关键字用于声明抽象类。

为什么我们必须使用界面:

  1. 界面是你的应用程序devise中最抽象的层次
  2. 接口支持多重inheritance。
  3. 为创build子类的描述签名而创build的接口
  4. 接口只有静态和最终的variables。
  5. 使用默认的方法来扩展一些接口,例如外部库。 但主要是这不是很好的做法:)

Remi Forax规则是你不用抽象类来devise。 你用接口devise你的应用程序 。 Watever是Java的版本,无论是什么语言。 它是由SOL I D原理中的I nterface分离原理支持的。

您可以稍后使用抽象类来分解代码。 现在使用Java 8,您可以直接在界面中执行此操作。 这是一个设施,不是更多。

何时应该使用默认方法的接口,何时应该使用抽象类?

向后兼容性:假设你的接口是由数百个类来实现的,修改这个接口将迫使所有的用户实现新添加的方法,尽pipe对于实现你的接口的许多其他类来说并不是必须的。另外,它允许你的接口成为一个function界面

事实与限制:

1 – 只能在接口中声明,不能在类或抽象类中声明。

2 – 必须提供一个机构

3-不像接口中使用的其他常规方法那样被认为是抽象的。

Java 8我们可以在interfaces使用具体的方法..对..那么它与Abstract类有什么不同呢? 记住一个抽象类是一个不能实例化的类(即不能创build对象),它可能包含方法体。 Java 8中的默认方法看起来类似于Abstract类,不是吗?

实际上我们会有所不同。 抽象类可以保持对象的状态。 它可以有构造函数和成员variables。 与Java 8默认方法的接口不能保持状态。 它不能有构造函数和成员variables。 您应该仍然使用Abstract类,只要您认为您的类可以具有状态,或者您需要在构造函数中执行某些操作 。 应该使用默认的方法来实现向后兼容。 无论何时您想在现有的传统界面中添加其他function,您都可以使用默认方法,而不会破坏任何现有的实施者类