特质 trait 是Scala中特有的一项特点,不同于C#与Java,如果一定要拿C#与Java中的某项特点作对比的话,最接近的应该是接口,但是C#与Java中的接口是不允许带有方法实现的,而Scala中的Trait是可以带有方法实现的。
定义特质:
预定义类是一样的只是关键字变了
trait XX{
def method (){ ...}
}
使用特质:
class F extends XX { }
这样既可以在F中直接使用特质XX的method了,因为特质中的method已经实现了,则不需要再重复实现。
*胖接口与瘦接口
相对于C#和Java的接口来说,Scala中的接口都相对较胖,因为Scala中可以带着实现方法,而C#与Java中则不可以,所以C#与Java的接口相对来说要瘦很多,而且相信大家都有过这种体验,就是经常同样的一个接口的不同实现,需要写很多重复的方法签名,所以Scala中的特质可以改变这个现象。
特质的堆叠:
因为特质是可以继承多个的,所以特质产生的效果也是可以堆叠的,例如:
// 定义一个抽象类,有一个方法get
abstract class IntSample{
def get(x : Int)
}
// 定义一个类继承自IntSample,get方法直接返回X
class BaseIntSample extends IntSample{
def get(x : Int){ x }
}
// 定义一个特质A,将返回的值 * 2
trait A extents IntSample{
abstract override def get(x: Int) { super.get( 2 * x ) }
}
// 定义一个特质B,将返回的值 +1
trait B extents IntSample{
abstract override def get(x: Int) { super.get( x + 1) }
}
// 定义一个实现类
val int = (new BaseIntSample with A with B)
int.get(1)
则,得到结果:4
理由是,执行时,先执行A的get,碰到了super则继续调用B的get,B的get返回了 2,则A继续执行,则返回4
如果将代码稍微修改下:
val int = (new BaseIntSample with B with A)
int.get(1)
则,返回值是 3。
特质相对于多重继承来说的好处是,他的结果是可以堆积的,而多重继承不可以。
特质的执行顺序,特质的执行顺序简单的说,就是从外向内一层层执行,如果两个特质继承自同一个类的时候,则先暂停该类的执行,再去执行另外的特质,直到这个类的所有子特质都执行完成:
其中的黑线是执行是顺序,白色箭头是继承关系。
因为Scala中的特质是动态混入的,所以运行时会消耗一些微乎其微的性能,但是因为执行顺序的问题,也可能会造成混乱,所以,具体的使用还需要多多考虑才行。