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

使用抽象类而不是特性(除了性能)的优点是什么? 在大多数情况下,抽象类似乎可以被特征取代。

我可以想到两个区别

  1. 抽象类可以有构造函数参数和types参数。 特质只能有types参数。 有一些讨论,即使在未来,特征也可以有构造参数
  2. 抽象类与Java完全互操作。 您可以在不使用任何包装的情况下从Java代码调用它们。 特征只有在不包含任何实现代码的情况下才能完全互操作

在Scala编程中有一个部分叫做“特质,还是不特性?” 这解决了这个问题。 由于第一版可以在网上find,所以我希望可以在这里引用所有的东西。 (任何认真的Scala程序员都应该购买这本书):

每当你实现一个可重用的行为集合,你将不得不决定是否要使用一个特质或一个抽象类。 没有确定的规则,但本节包含一些要考虑的指导原则。

如果行为不会被重用 ,那就把它作为一个具体的类。 毕竟这不是可重用的行为。

如果它可能被重复使用在多个不相关的类中 ,那就把它作为一个特征。 只有特质可以混合到类层次结构的不同部分。

如果您想在Java代码中inheritance它 ,请使用抽象类。 由于具有代码的特征不具有密切的Java模拟,所以从Java类中的特征inheritance是非常困难的。 同时从Scala类inheritance,就像inheritance自Java类。 作为一个例外,只有抽象成员的Scala特性可以直接转换为Java接口,所以即使您希望Java代码inheritance它,也应该自由地定义这些特性。 有关使用Java和Scala的更多信息,请参见第29章。

如果你打算以编译的forms发布它 ,并且你期望外部团体编写inheritance它的类,你可能会倾向于使用抽象类。 问题是,当一个特性获得或失去一个成员时,即使没有改变,任何从其中inheritance的类也必须重新编译。 如果外部客户只会调用行为,而不是inheritance,那么使用特质就没有问题。

如果效率是非常重要的 ,倾向于使用一个类。 大多数Java运行时对类成员的虚拟方法调用是比接口方法调用更快的操作。 特征被编译到接口,因此可能会支付一些性能开销。 但是,只有当你知道这个特征构成了一个性能瓶颈,并且有证据表明使用一个类实际上解决了这个问题的时候,你才应该做出这个select。

如果你仍然不知道 ,考虑到以上,然后开始作为一个特质。 你可以随时改变它,一般来说,使用特质可以打开更多的选项。

正如@Mushtaq Ahmed所提到的,一个特征不能有任何parameter passing给一个类的主构造函数。

super另一个区别就是治疗。

类与性状之间的另一个区别在于,在类中, super调用是静态的,在性质上是dynamic的。 如果你在类中写入super.toString ,你确切知道哪个方法的实现将被调用。 然而,当你在一个trait中写同样的东西的时候,当你定义trait的时候,调用super调用的方法实现是不确定的。

有关更多细节,请参阅第12章的其余部分。

编辑:

抽象类的行为与特征的方式有细微的差别。 其中一个线性化规则是保留了类的inheritance层次,这往往会在链中稍后推送抽象类,而特性则可以高兴地混入其中。在某些情况下,实际上最好是在类的线性化的后一个位置,所以抽象类可以用于此。 请参阅在Scala中约束类线性化(mixin order) 。

无论什么是值得的,Odersky等人的Scala编程build议,当你怀疑时,你使用特征。 如果需要,您可以随时将它们更改为抽象类。

除了不能直接扩展多个抽象类,但是可以将多个特征混合到一个类中,值得一提的是,特征是可堆栈的,因为特征中的超级调用是dynamic绑定的(它指的是之前混合的类或特征当前一个)。

从托马斯的“ 抽象类与特质的区别”的回答:

 trait A{ def a = 1 } trait X extends A{ override def a = { println("X") super.a } } trait Y extends A{ override def a = { println("Y") super.a } } scala> val xy = new AnyRef with X with Y xy: java.lang.Object with X with Y = $anon$1@6e9b6a scala> xy.a Y X res0: Int = 1 scala> val yx = new AnyRef with Y with X yx: java.lang.Object with Y with X = $anon$1@188c838 scala> yx.a X Y res1: Int = 1 

当扩展一个抽象类时,这表明该子类是一个类似的类。 我认为,在使用特质时,情况并非如此。

在Scala编程中 ,作者说,抽象类将经典对象定义为“是 – ”关系,而特征则是构成的一个缩影。

抽象类可以包含行为 – 他们可以使用构造函数参数(哪些特征不能)和表示一个工作实体。 特征代替了一个特征,即一个function的接口。