是否可以抽象类替换接口?

在Java中,您可以创建仅包含抽象方法的抽象类。 另一方面,您可以创建一个声明相同方法的接口。 既然如此,你可以使用抽象类而不是接口吗?

不总是:

  • 一个类只能扩展一个
  • 一个类可以实现多个接口

Sun文档进行了更详细的比较:

抽象类与接口

与接口不同,抽象类可以包含非静态和最终的字段,并且它们可以包含已实现的方法。 这些抽象类与接口类似,不同之处在于它们提供部分实现,将其留给子类来完成实现。 如果抽象类只包含抽象方法声明,则应将其声明为接口。

多个接口可以由类层次结构中的任何位置的类实现,无论它们是否以任何方式彼此相关。 例如,可以考虑可比较或可克隆。

相比之下,抽象类最常被子类化以共享实现部分。 单个抽象类由具有许多共同点(抽象类的已实现部分)的类似类子类化,但也有一些差异(抽象方法)。

在某些情况下,您可以使用抽象类而不是接口。 但是,这样做几乎不是一个好主意。 通常,您应该使用以下规则:

  1. 接口指定行为。
  2. 抽象类指定实现。

使用抽象类的另一个“问题”是,您可以不再实现mixins,即可以实现多个接口,但是您只能扩展一个抽象类。

这里的答案中缺少的一点是谁将实现界面的想法。

如果组件想要将抽象类型的实例返回给其调用者,其中具体类型在内部定义并且对调用者隐藏,则使用接口 。 相反,如果您的组件使用或接受 其调用者必须实现的抽象类型实例,则抽象类 通常是更好的选择。

预期进化和维持二进制兼容性提示了这里的规模。 使用抽象类,您可以添加方法,如果您提供基本实现,抽象类的现有实现将继续正常工作。 使用接口,添加方法会破坏二进制兼容性,因为没有现有的实现可以继续正确编译而无需更改以定义新方法。

Apache Cactus项目就如何解决这些义务进行了很好的讨论 。

要回答你的问题,是的,你可以使用抽象类(不提供实现)而不是接口,但我会考虑这种不好的做法:

  • 你已经用完了inheritance的“一次性”(没有获得任何好处)。
  • 您不能从多个抽象类inheritance,但可以实现多个接口。

我希望在你希望提供类的部分实现的情况下更多地使用抽象类,可能会将某些行为委托给具体的子类实现。

  • java中的类可以从多个接口inheritance,但只能从一个抽象类inheritance。

  • 接口不能定义任何代码,在抽象类中,您可以定义代码(即方法的默认行为)

抽象类和接口是互补的。

例如,在创建API时,您需要向客户端提供接口,以便您可以始终完全更改实现,而他不必更改其代码,并且用户在使用API​​构建时不依赖于实现,而只是在方法合同。

然后,您将拥有部分实现这些接口的抽象类,以便

  • 共享一些公共代码,这些代码可能在接口的所有(或几乎所有)实现中使用,这很明显
  • 提供可以在“真实”实现中重写的默认行为,例如使用interfaces方法创建实现的文本表示的toString()方法
  • 在接口更改后保留实现兼容性,例如在接口中添加新方法时,还要在抽象类中添加默认实现,以便扩展抽象类的实现(例如用户创建的实现)仍可在不更改的情况下工作

接口更清洁,重量更轻。 抽象类使您严重依赖它,因为您无法扩展任何其他类。

看看有趣的文章“ 为什么扩展是邪恶的 ”来了解接口实现和类inheritance之间的差异(除了显而易见的多单一限制)

你应该使用哪些,抽象类或接口?

如果任何这些语句适用于您的情况,请考虑使用抽象类:

  • 您希望在几个密切相关的类之间共享代码。
  • 您希望扩展抽象类的类具有许多常用方法或字段,或者需要除公共之外的访问修饰符(例如protected和private)。
  • 您想声明非静态或非最终字段。 这使您可以定义可以访问和修改它们所属对象的状态的方法。

如果任何这些语句适用于您的情况,请考虑使用接口:

  • 您希望不相关的类将实现您的接口。 例如,Comparable和Cloneable接口由许多不相关的类实现。
  • 您希望指定特定数据类型的行为,但不关心谁实现其行为。
  • 您希望利用类型的多重inheritance。

有关更多详细信息,请参阅oracle文档链接

抽象类是Abstraction的部分实现,而Interfaces是Abstraction的完全实现。在Abstract类中我们可以将方法声明和方法体放在一起。 我们不能创建抽象类(关联)的对象,并通过inheritance(而不是关联)重用该类。 默认情况下,在接口中,所有声明的变量都是静态final,所有方法都是public。

例如:在JDK中只有很少的抽象类,而HttpServlet就是Servlet中使用的其中之一。所以我们不能创建HttpServlet的对象,它只能通过inheritance来使用。

接口的主要用途是创建接口的引用并调用在运行时解析的特定类的方法。 因此,创建接口的引用以调用该方法总是更好的主意。

接口只能保存抽象方法,接口也可以实现任何类的多个接口。 但抽象持有抽象和非抽象方法,而抽象方法不能扩展到多于一个类。