一,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也没关系,只是将它”拿了出来“,不执行而已
--------------------------------------------------------------------------------------------------------------------
以上,全是我个人的想法,不喜的请略过。。。。