一、理解:
一个类的父类或者混入的多个特征中,具有相同签名的方法,如果该方法不是来自同一个祖宗。。则会出错。必须在当前类重写该方法才能正确执行(这里与java多继承接口一样)
反例代码:
object Test{
def main(args:Array[String]): Unit ={
val son = new Son
son.a()
}
}
class Son extends Father with TestTrait1 with TestTrait2 {
}
class Father {
override def a():Unit={
println("father")
}
}
trait TestTrait1 {
override def a(): Unit ={
println("TestTrait1")
}
}
trait TestTrait2 {
override def a(): Unit ={
println("TestTrait2")
}
}
执行main方法报错如下:
正例代码:
object Test{
def main(args:Array[String]): Unit ={
val son = new Son
son.a()
}
}
class Son extends Father with TestTrait1 with TestTrait2 {
}
class Father extends Operate {
override def a():Unit={
println("father")
}
}
trait Operate{
def a():Unit={
println("Operate")
}
}
trait TestTrait1 extends Operate{
override def a(): Unit ={
println("TestTrait1")
}
}
trait TestTrait2 extends Operate{
override def a(): Unit ={
println("TestTrait2")
}
}
输出结果:
通过正例可以知道,最终生效的其实是Son声明时extends和with的特质列表中最右边的特质的a方法。。。
二、super的使用
(1)就是当最右边的特征的a方法中使用super.a;此时super.a会执行什么?
答案:super调用a方法在scala中是调用上一级的a方法。
什么是上一级?
在extends和with的特征列表,从右往左看,最右边的第一个特征的上一级是最右边第二个特征,最右边第二个特征的上一级是最右边第三个特征。
即最右边的使用TestTrait3 的a方法中的super.a代码,该会调用最右边倒数第二个具有a方法的特征,然后如果最右边倒数第二个特征的a方法也有super.a,那么就会继续从右往左类推。
注意:如果右往左过程中,某个特质没有a方法,那么上一级应该是越过该特征的更左边一个特征。。并且包含Son继承的Father类中的a方法。。因为Father类的a方法也是与其他特征一样来自于同一个父特征。。
示例代码:
package com.atgui.bigdata.scala.chapter01
/**
* @Author 周利东
* @Date: 2019/11/17 17:53
*/
object Test {
def main(args: Array[String]): Unit = {
val son = new Son
son.a()
}
}
class Son extends Father with TestTrait1 with TestTrait2 with TestTrait3 {
}
class Father extends Operate {
override def a(): Unit = {
println("father")
super.a()
}
}
trait Operate {
def a(): Unit = {
println("Operate")
}
}
trait TestTrait1 extends Operate {
override def a(): Unit = {
println("TestTrait1")
super.a
}
}
trait TestTrait2 extends Operate {
override def a(): Unit = {
println("TestTrait2")
super.a
}
}
trait TestTrait3 extends Operate {
override def a(): Unit = {
println("TestTrait3")
super.a
}
}
输出结果:
TestTrait3
TestTrait2
TestTrait1
father
Operate
(3)如果super想要调用的不是上一级的a,而是上一级的上一级的a方法,又或者更上级的呢?
使用 super[指定父亲].a 。
因为Son有多个父亲(定义Son是继承的类和混入的特征都算父亲),所以可以使用super加方括号指定要调用哪一个父亲的a方法。。
object Test{
def main(args:Array[String]): Unit ={
val son = new Son
son.invokeFather()
son.invokeFather2()
son.invokeFather3()
}
}
class Son extends B1 with B2{
def invokeFather(): Unit ={
super.a()
}
def invokeFather2(): Unit ={
super[B2].a() //与super.a()是一样的
}
def invokeFather3(): Unit ={
super[B1].a()
}
}
trait A{
def a():Unit={
println("A")
}
}
trait B1 extends A{
override def a(): Unit ={
println("B1")
}
}
trait B2 extends A{
override def a(): Unit ={
println("B2")
}
}
输出结果如下:
B2
B2
B1
(4)不论是在java中还是scala中,都无法实现通过super调用父类的父类(爷爷)中的a方法,super只能调用父类和上一级。具体可以看这篇:https://www.cnblogs.com/miaobing/p/5274944.html
我也写了个示例:
object Test{
def main(args:Array[String]): Unit ={
val son = new Son
son.invokeFather()
son.invokeFather2()
son.invokeFather3()
}
}
class Son extends B{
def invokeFather(): Unit ={
super.a()
}
def invokeFather2(): Unit ={
super[B].a()
}
def invokeFather3(): Unit ={
super[A].a()
}
}
trait A{
def a():Unit={
println("A")
}
}
trait B extends A{
override def a(): Unit ={
println("B")
}
}
报错如下:
还有个很大的问题。。
上面讲的都是指那些特征的父亲都是同一个,而不是祖宗是同一个。。。
如果他们的父亲不一定相同,而是祖宗链中存在相同的一个祖宗(有a方法的那个),那么前面讲的super调用上一级就失效了,调用的不一定是上一级。。而是按辈分来看。。请看示例代码:
object Test{
def main(args:Array[String]): Unit ={
val son = new Son
son.a()
}
}
class Son extends C with E with B{}
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()
}
}
本以为执行结果是:B E C A
然而实际上的结果是:
B
E
D
C
A
关于这个问题,其实是我还没理解透彻scala的super动态绑定,另外又写了一篇文章。花了三小时。
请看:https://blog.csdn.net/qq_36951116/article/details/103137762