使用抽象类而不是特征有什么好处?
使用抽象类而不是特征有什么优点(除了性能之外)?在大多数情况下,抽象类似乎可以被特征代替。
What is the advantage of using an abstract class instead of a trait (apart from performance)? It seems like abstract classes can be replaced by traits in most cases.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我可以想到两个区别:
I can think of two differences
《Scala 编程》中有一节名为 “要特质,还是不要特质?” 这解决了这个问题。由于第一版可以在线获取,我希望可以在这里引用整个内容。 (任何认真的 Scala 程序员都应该购买这本书):
正如 @Mushtaq Ahmed 提到的,特征不能将任何参数传递给类的主构造函数。
另一个区别是对 super 的处理。
有关更多详细信息,请参阅第 12 章的其余部分。
编辑 1 (2013):
与特征相比,抽象类的行为方式存在细微差别。线性化规则之一是它保留了类的继承层次结构,这往往会将抽象类推到链的后面,而特征可以愉快地混合在一起。在某些情况下,实际上最好处于类线性化的后面位置,因此可以使用抽象类来实现这一点。请参阅在 Scala 中约束类线性化(混合顺序)。
编辑 2 (2018):
从 Scala 2.12 开始,trait 的二进制兼容性行为已发生变化。在 2.12 之前,向特征添加或删除成员需要重新编译继承该特征的所有类,即使这些类没有更改。这是由于 JVM 中特征的编码方式造成的。
从 Scala 2.12 开始,traits 编译为 Java 接口,所以要求放宽了一些。如果该特征执行以下任何操作,则其子类仍然需要重新编译:
以查找正确超级特征中的实现,但如果该特征没有,您现在可以在不破坏二进制兼容性的情况下更新它。
There's a section in Programming in Scala called "To trait, or not to trait?" which addresses this question. Since the 1st ed is available online, I'm hoping it's OK to quote the whole thing here. (Any serious Scala programmer should buy the book):
As @Mushtaq Ahmed mentioned, a trait cannot have any parameters passed to the primary constructor of a class.
Another difference is the treatment of
super
.See the rest of Chapter 12 for more details.
Edit 1 (2013):
There is a subtle difference in the way abstract classes behaves compared to traits. One of the linearization rules is that it preserves the inheritance hierarchy of the classes, which tends to push abstract classes later in the chain while traits can happily be mixed in. In certain circumstances, it's actually preferable to be in latter position of the class linearization, so abstract classes could be used for that. See constraining class linearization (mixin order) in Scala.
Edit 2 (2018):
As of Scala 2.12, trait's binary compatibility behavior has changed. Prior to 2.12, adding or removing a member to the trait required recompilation of all classes that inherit the trait, even if the classes have not changed. This is due to the way traits were encoded in JVM.
As of Scala 2.12, traits compile to Java interfaces, so the requirement has relaxed a bit. If the trait does any of the following, its subclasses still require recompilation:
But if the trait does not, you can now update it without breaking binary compatibility.
无论其价值如何,Odersky 等人的 Scala 编程 建议,当您怀疑,你使用特质。如果需要的话,您可以稍后将它们更改为抽象类。
For whatever it is worth, Odersky et al's Programming in Scala recommends that, when you doubt, you use traits. You can always change them into abstract classes later on if needed.
除了不能直接扩展多个抽象类,但可以将多个特征混合到一个类中之外,值得一提的是,特征是可堆叠的,因为特征中的超级调用是动态绑定的(它引用之前混合的类或特征)当前的一个)。
来自托马斯在抽象类和特征之间的差异中的回答:
Other than the fact that you cannot directly extend multiple abstract classes, but you can mixin multiple traits into a class, it's worth mentioning that traits are stackable, since super calls in a trait are dynamically bound (it is referring a class or trait mixed before current one).
From Thomas's answer in Difference between Abstract Class and Trait:
当扩展一个抽象类时,这表明子类是类似的。我认为使用特征时不一定是这种情况。
When extending an abstract class, this shows that the subclass is of a similar kind. This is not neccessarily the case when using traits, I think.
在 Scala 编程 中,作者说抽象类使经典的面向对象“是- a”关系,而特征是一种阶梯式的组合方式。
In Programming Scala the authors say that abstract classes make a classical object oriented "is-a" relationship while traits are a scala-way of composition.
抽象类可以包含行为 - 它们可以使用构造函数参数进行参数化(特征不能)并表示工作实体。相反,特征仅代表一个功能,一个功能的接口。
Abstract classes can contain behaviour - They can parameterized with constructor args (which traits can't) and represent a working entity. Traits instead just represent a single feature, an interface of one functionality.