看前须知:
可以先看总结,看不明白再把示例代码复制到编译器中,然后对照着我的文字讲述一步一步看过去。请耐心看下去。否则你就不一定能看懂了。(写了三小时,网上几乎没资料)
如果有更好的关于这方面的资料,希望有朋友能推荐一下。。。我的文笔写出来估计也就我能看懂了。
代码:
object Test {
def main(args: Array[String]): Unit = {
val son = new Son
son.a()
}
}
class Son extends C with G with E with H with F with B {}
trait H {
// def a(): Unit = {
// println("A")
// }
}
trait A {
def a(): Unit = {
println("A")
}
}
trait B extends A {
override def a(): Unit = {
println("B")
super.a()
}
}
trait C extends A {
override def a(): Unit = {
println("C")
super.a()
}
}
trait D extends A {
override def a(): Unit = {
println("D")
super.a()
}
}
trait E extends D {
override def a(): Unit = {
println("E")
super.a()
}
}
trait F extends D {
override def a(): Unit = {
println("F")
super.a()
}
}
trait G extends E {
override def a(): Unit = {
println("G")
super.a()
}
}
输出结果:
B
F
G
E
D
C
A
描述:
super动态绑定调用链规则:
1、Son混入或者继承的多个trait中(例子中是B、F、E、G、C)如果有相同的方法a,
那么这些具有a方法的trait或者class(例子中是B、F、E、G、C)都必须继承自同一个祖宗(例子中是A),并且a方法源头必须是该祖宗(例子中是A)。(不用管是否被重写过,没影响)
2、如果在这多个trait中,某个trait的也有相同的a方法,并且不是来自于同一个祖宗(A),那么执行时就会报错。
比如例子中,Son还混入了H,H与其他trait没有关系,如果在H中添加一个相同签名的a方法,那么程序运行就会报错。
3、继续接着步骤1:此时当调用Son实例的a方法时,使用super就会按动态绑定规则调用混入的trait的a方法。
4、super动态绑定规则:
(1)调用Son的a方法时,Son中没有重写a方法,那么执行的a方法就按定义Son代码时继承和混入的trait的顺序从右往左看。
(2)具有a方法的trait按顺序排列:C、G、E、F、B ,H被去掉了,因为H没有a方法。
(3)然后再看看步骤(2)中剩下的这些trait中是否有继承关系的,如果有存在继承关系的,把存在继承关系中的辈分最小的留下,具体例子:根据代码知道,E和G是有继承关系的,并且是G继承自E,所以G的辈分最小,留下G,去掉E。
此时具有a方法的trait按顺序排列:C、G、F、B。
(4)从右往左执行,调用son的a方法,此时调用的是最右边的B的a方法,打印"B",
(5)然后执行B的super.a(),B左边的是F,F的辈分小于B的辈分,所以此时是从右往左执行,调用F的a方法,打印"F",
(6)然后执行F的super.a(),F左边的是G,G的辈分小于F的辈分,所以此时是从右往左执行,调用G的a方法,打印"G",
(7)然后执行G的super.a(),G左边的是C,C的辈分大于G的辈分,不能像(5)和(6)一样执行,此时G的super.a向上调用G的继承链中的祖宗的a方法,当调用的祖宗与C是同一辈分时,调用完后再继续按照从右往左规则执行。
具体如下:
- G的继承关系由近到远有:G、E、D、A,而C的继承关系由近到远有:C、A,所以G的祖宗里,只有D与C是同一辈分的。然后就会一直向上调用D。
- 所以G的super.a会调用E的a方法,打印"E"。
- 然后E的super.a()会调用D的a方法,打印"D"。
- D与 C是同一辈分(同样是A的下一代),所以此时D的super.a()就继续按照从右往左规则执行,调用的是C的a方法,打印"C"。
G这边就执行完了。
(8)C已经是最左边的了,super调用开始向C的继承链上调用,C的super.a调用C的父亲(A)的a方法,打印"A"。
至此,调用son的a方法执行完闭。
上述步骤中,只要过程中有一个缺少super调用的,那么就不会继续执行下去。
总结
super动态绑定规则:
(1)从右往左执行,
如果左边的trait辈分小于等于当前的trait,那么super调用左边的这个trait。
如果在左边的trait辈分比当前的trait大,那将会从当前trait的继承链中往上调用,直到调用到的祖宗与左边trait辈分一样
(2)然后继续从右往左执行,即继续调用左边的trait。
(3)如果当前调用的trait已经是最左边的trait,且此时还有super调用,那么就会往当前trait的继承链中往上调用,直到没有super调用为止。
(4)上述三步中,只要过程中有一个缺少super调用的,那么就不会继续执行下去。