为了账号安全,请及时绑定邮箱和手机立即绑定

使用抽象类而不是特征的优点是什么?

使用抽象类而不是特征的优点是什么?

翻过高山走不出你 2020-02-03 14:45:15
使用抽象类而不是特征(除了性能)有什么好处?在大多数情况下,抽象类似乎可以用特征代替。
查看完整描述

3 回答

?
眼眸繁星

TA贡献1873条经验 获得超9个赞

我可以想到两个差异

  1. 抽象类可以具有构造函数参数以及类型参数。特性只能具有类型参数。有人讨论过,即使将来特征也可以具有构造函数参数

  2. 抽象类可与Java完全互操作。您可以从Java代码中调用它们而无需任何包装。特性只有在不包含任何实现代码的情况下才可以完全互操作


查看完整回答
反对 回复 2020-02-03
?
阿晨1998

TA贡献2037条经验 获得超6个赞

Scala编程中有一节称为“是特质还是不特质?”。解决了这个问题。由于第一版可在线获得,我希望可以在这里引用整个内容。(任何认真的Scala程序员都应该买这本书):

每当实现行为的可重用集合时,您都必须决定要使用特征还是抽象类。没有严格的规则,但是本节包含一些要考虑的准则。

如果该行为不会被重用,则将其设为一个具体的类。毕竟这不是可重用的行为。

如果可以在多个不相关的类中重用它,请使其成为特征。只有特征可以混入类层次结构的不同部分。

如果要在Java代码中从中继承,请使用抽象类。由于具有代码的特征没有紧密的Java类似物,因此从Java类中的特征继承往往很尴尬。同时,从Scala类继承也与从Java类继承一样。唯一的例外是,仅具有抽象成员的Scala特性直接转换为Java接口,因此即使您期望Java代码从其继承,您也可以随意定义这些特性。有关如何一起使用Java和Scala的更多信息,请参见第29章。

如果打算以编译形式分发它,并且希望外部团体编写从其继承的类,则可能倾向于使用抽象类。问题在于,当一个特性获得或失去一个成员时,任何从其继承的类都必须重新编译,即使它们没有更改。如果外部客户只会调用行为,而不是继承行为,那么使用特征就可以了。

如果效率很重要,则倾向于使用课程。大多数Java运行时使对类成员的虚拟方法调用比接口方法调用更快。特性被编译到接口,因此可能会付出一些性能开销。但是,仅当您知道所讨论的特征构成性能瓶颈并有证据证明使用类实际上可以解决问题时,才应做出此选择。

如果仍然不知道,请在考虑了上述内容之后,将其作为特征开始。您以后总是可以更改它,通常使用特征可以使更多选项保持打开状态。

正如@Mushtaq Ahmed提到的,特征不能将任何参数传递给类的主构造函数。

另一个区别是治疗super

类和特性之间的另一个区别是,在类中,super调用是静态绑定的,而在特性中,它们是动态绑定的。如果您super.toString在类中编写代码,那么您将确切知道将调用哪种方法实现。但是,当您在特征中编写相同内容时,定义特征时,用于超级调用的方法实现是不确定的。

有关更多详细信息,请参见第12章的其余部分。

编辑1(2013):

与特质相比,抽象类的行为方式存在细微差异。线性化规则之一是,它保留了类的继承层次结构,这倾向于将抽象类推到链的后面,而特征可以很容易地混合进来。在某些情况下,实际上最好放在类线性化的后一个位置,因此可以使用抽象类。请参阅Scala中的约束类线性化(混合顺序)。

编辑2(2018):

从Scala 2.12开始,特征的二进制兼容性行为已更改。在2.12之前,向特性添加或删除成员都需要重新编译所有继承特性的类,即使这些类没有更改。这是由于在JVM中对特征进行编码的方式所致。

从Scala 2.12开始,特征可以编译到Java接口,因此要求有所放松。如果特征执行以下任何一项操作,则其子类仍需要重新编译:

  • 定义字段(valvar,但是常量可以- final val没有结果类型)

  • 呼唤 super

  • 主体中的初始化器语句

  • 扩展课程

  • 依靠线性化在正确的特征中找到实现

但是,如果特征不具备,您现在可以在不破坏二进制兼容性的情况下对其进行更新。


查看完整回答
反对 回复 2020-02-03
  • 3 回答
  • 0 关注
  • 639 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信