scala中类继承的类和混入的特征trait中具有相同签名的方法时,会出现什么问题?(与java的有些不同)

一、理解:

一个类的父类或者混入的多个特征中,具有相同签名的方法,如果该方法不是来自同一个祖宗。。则会出错。必须在当前类重写该方法才能正确执行(这里与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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值