trait类似于java中的interface.可以在类和对象上,扩展其特性,包括对象的属性还有行为。但是特质不能被实例化,因此特质没有参数。
在class或者object继承多个trait的时候,有可能出现diamond问题。如下图:
image.png
上图中的代码如图所示:
trait Animal {
def talk: String
}
trait Cat extends Animal {
override def talk: String = "I am Cat"
def hello:Unit={
println("hello")
}
}
trait Dog extends Animal {
def talk: String = "I am Dog"
}
trait Monkey extends Animal {
def talk: String = " i am a monkey"
}
object TestTrait extends Dog with Cat with Monkey {
def main(args: Array[String]): Unit = {
println(this.talk)
}
}
但是很不幸,上面的代码编译会报错。
为什么报错,首先我们先来看trait继承的时候的linerization.红色的箭头,就是trait线性化之后的trait 叠加流向。 TestTrait ==》Monkey ==》Cat ===》Dog==>Animal
然后我们来看,后面几个特性都具有的方法 talk .Monkey是没有override的,然后Cat是有override 的,然后Dog是没有override的。那么TestTrait对talk方法到底重写不重写呢。
编译器就不会通过。对于特性的方法,要么只有一个没有override的talk方法,因为只有一个,所以他肯定调用这个talk方法。要么前面有很多个talk方法。后面有大于等于1个连续的override。最后override掉方法。我有一个比较好方法去理解这个。就像叠立方型的木块。在trait linerization 链条中。第一个设一个固定的面积值。比如6 。假如后面没有override.那么面积小了,比如说5.。那我们能看见两个木块,到底选哪个呢。编译器也不知道。假如有override ,面积大了,比如说7 ,就会覆盖掉前面的,只能看到最上面的那个方法,假如这个时候又来一个方法没有override,又变小了,那又是可以看见两个方块。所以编译器又困惑了。
总而言之,就是在trait linerization 链条中,Monkey ==》Cat ===》Dog==>Animal,两种情况。
1 只有一个没有override的方法
2 大于等于1个没有override,并且连续,然后跟着若干个连续的override.
所以上面的只要把Monkey的talk方法override掉。
然后具体的如何线性化特性,请看这边文章
网友评论