关于scala利用特质实现多继承的冲突解决机制及叠加的特质

一,Scala的构造顺序:这里指创建类时拓展一个超类及一个或多个特质,或者创建类对象时混入特质时的构造顺序。(只有单个类时必然没有什么顺序可言)

           

         假设有个父特质trait,trait1,trait2是其子特质:

         class child extends parent with trait1 with trait2

        构造顺序如下:parent->trait->trait1->trait2

首先执行超类的构造器,然后是特质的,最后才是子类的;特质的构造器是从左到右依次构造,每个特质先构造其父特质,再构造子特质。

二。叠加的特质:

先放一个整体的代码:

trait Loggered{
  def log(a:String){println(a)}
}
class SavingsAccount extends Account with Loggered {
  def withdraw(amount: Int){
    if(amount>balance)log ("insufficient founds")   //什么也不会输出。。因为loggered这个特质里面的log方法体为空
    else balance -= amount
  }
}
class Account{
  var balance=500
}
trait TimestampLogger extends Loggered{
  override def log(msg: String): Unit ={
    super.log(new java.util.Date()+" "+msg)
  }
}
trait TimeShortLogger extends Loggered{
  val maxLength=15
  override def log(msg: String){
    super.log(
      if(msg.length<=maxLength)msg else msg.substring(0,maxLength-3)+"..."
    )
  }
}
object test9{
  def main(args:Array[String]): Unit ={
    val acc1=new SavingsAccount with ConsoleLogger with TimestampLogger
    val acc2=new SavingsAccount with ConsoleLogger with TimeShortLogger with TimestampLogger   //从左到右执行特质,遇见super执行左边的特质(左边的特质相当于其临时父类),
    // 如果左边没有特质了,super指向的就是当前特质的父特质

    acc1.log("zdzzzzzzzzzzzzz")
    acc2.withdraw(2000)
  }
}
trait ConsoleLogger extends Loggered{             //对Loggered特质的改进
  override def log(msg:String){super.log(msg)}      //override 不能省略
}

---首先不管叠加几个特质,都是扩充类里面的功能而已,可以看作一个整体。。整个new 后面的一坨其实是匿名子类(超类加入了特质形成了一个”匿名子类“--就是一个新类),还可以直接在定义类那加入这两个特质--最后效果一样 。注意不能将父特质与子特质一起混入/拓展于同一个对象/类里面

----这里的vcc2.withdraw调用的是SavingsAccount里的方法。然后这个方法又调用了log方法,

而log方法是后面那一堆特质提供的。具体步骤如下:

将 "insufficient founds" 这个字符串传入到混入时最右边的特质

然后挨个向左执行(super.log.....)直到第一个特质,此时的super调用的是它的父类(也就是他左边的特质,如果左边没有特质,调用的就是它的父特质loggered) 。。

如果没有super,单纯将许多个特质中的方法,字段加入到这个类中而已。。有同名的  不   会报错

为什么呢?提出如下假设:

构造方法执行的顺序避免了菱形继承???只调用第一个出现的那个方法?(这里是最后一个特质的log方法)

我将特质按着从右往左的执行顺序,更改了下代码,按顺序输出1,2,3,4...:

trait Loggered{
  def log(a:String){println("4")}
}
class SavingsAccount extends Account with Loggered {
  def withdraw(amount: Int){
    if(amount>balance)log ("insufficient founds")   //什么也不会输出。。因为loggered这个特质里面的log方法体为空
    else balance -= amount
  }
}
class Account{
  var balance=500
}
trait TimestampLogger extends Loggered{
  override def log(msg: String): Unit ={
    println(new java.util.Date()+ " 1 " +msg)
  }
}
trait TimeShortLogger extends Loggered{
  val maxLength=15
  override def log(msg: String){
    println("2 ")
  }
}
trait ConsoleLogger extends Loggered{             //对Loggered特质的改进
  override def log(msg:String): Unit ={
    println(" 3")
  }      //override 不能省略
}

object test9{
  def main(args:Array[String]): Unit ={
    val acc1=new SavingsAccount with ConsoleLogger with TimestampLogger
    val acc2=new SavingsAccount with ConsoleLogger with TimeShortLogger with TimestampLogger   //从左到右执行特质,遇见super执行左边的特质(左边的特质相当于其临时父类),
    // 如果左边没有特质了,super指向的就是当前特质的父特质

    acc2.withdraw(2000)
  }
}

运行结果:

 确实只调用了最右边的那个特质的log。。。

--但是从父类与特质中继承一个同名的方法,就会报错。。。。!!!!!!!!!!!!!!!!!!!

 三,上面就是多继承时出现的问题了,它没法判断log方法是来自Account这个超类呢还是来自特质呢。。

--为什么类不能有像特质这样的机制呢,特质之所以可以,是因为他们都继承与同一个父特质,或者相互之间有继承关系--总之有一模一样的方法头,而且需要重写。。。(归功于--有个override执行到当前特质时,我管这里有几个同样的log方法呢,我重写了,调用的就是现在我自己的log)只要有一个特质没有继承这个父特质,那么就会报错

为什么只输出1呢。。。。因为后面的log方法没调用呀。。。。。。。。。。。。

 

测一下:这里TimeShortLogger 继承的不是Loggerede了,我让他继承TimstampLogger,

首先,没有报错,证明上一段话中目前看来是没错的。其次,这里输出的是2:

---也就是说首先调用的是TimeShortLogger里面的构造器

这里就跟构造顺序有关了。。。构造顺序如下:

SavingsAccount - > Loggered -> ConsoleLogger -> TimestampLogger -> TimeShortLogger

---这里应该是有一个栈之类的东西,按照构造顺序,构造完一个特质就入栈,等所有的特质构造完了就挨个出栈,然后利用super 挨个调用。。没有super也没关系,只是将它”拿了出来“,不执行而已

--------------------------------------------------------------------------------------------------------------------

以上,全是我个人的想法,不喜的请略过。。。。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值