ing]): Unit = {
//说明
//1. 创建 MySQL实例时,动态的混入 DB 和 File
//研究第一个问题,当我们创建一个动态混入对象时,其顺序是怎样的
//总结一句话
//Scala在叠加特质的时候,会首先从后面的特质开始执行(即从左到右)
//1.Operate...
//2.Data
//3.DB
//4.File
val mysql = new MySQL with DB with File
println(mysql)
//研究第2个问题,当我们执行一个动态混入对象的方法,其执行顺序是怎样的
//顺序是,(1)从右到左开始执行 , (2)当执行到super时,是指的左边的特质 (3) 如果左边没有特质了,则super就是父特质
//1. 向文件"
//2. 向数据库
//3. 插入数据 100
mysql.insert(100)
println("===================================================")
//练习题
val mySQL = new MySQL with File with DB
mySQL.insert(999)
//构建顺序
//1.Operate...
//2.Data
//3.File
//4.DB
//执行顺序
//1. 向数据库
//2. 向文件
//3. 插入数据 = 999
}
}
trait Operate { //特点
println("Operate...")
def insert(id: Int) //抽象方法
}
trait Data extends Operate { //特质,继承了Operate
println("Data")
override def insert(id: Int): Unit = { //实现/重写 Operate 的insert
println("插入数据 = " + id)
}
}
trait DB extends Data { //特质,继承 Data
println("DB")
override def insert(id: Int): Unit = { // 重写 Data 的insert
println("向数据库")
super.insert(id)
}
}
trait File extends Data { //特质,继承 Data
println("File")
override def insert(id: Int): Unit = { // 重写 Data 的insert
println("向文件")
//super.insert(id) //调用了insert方法(难点),这里super在动态混入时,不一定是父类
//如果我们希望直接调用Data的insert方法,可以指定,如下
//说明:super[?] ?的类型,必须是当前的特质的直接父特质(超类)
super[Data].insert(id)
}
}
class MySQL {} //普通类
-叠加特质注意事项和细节
1) 特质声明顺序从左到右
2) Scala 在执行叠加对象的方法时,会首先从后面的特质(从右向左)开始执行
3) Scala 中特质中如果调用 super,并不是表示调用父特质的方法,而是向前面(左边)继续 查找特质,如果找不到,才会去父特质查找
4) 如果想要调用具体特质的方法,可以指定:super[特质].xxx(...).其中的泛型必须是该特质的直接超类类型
8.4.6 当作富接口使用的特质
富接口:即该特质中既有抽象方法,又有非抽象方法
trait Operate {
def insert(id: Int) //抽象
def pageQuery(pageno: Int, pagesize: Int): Unit = { //实现
println("分页查询")
}
}
8.4.7 特质中的具体字段
特质中可以定义具体字段,如果初始化了就是具体字段,如果不初始化就是抽象字段,混入该特质的类就具有了该字段,字段不是继承,而是直接加入类,成为自己的字段
object boke_demo01 {
def main(args: Array[String]): Unit = {
val mySQL = new MySQL with DB {
override var sal = 10
}
}
}
trait DB {
var sal: Int //抽象字段
var opertype: String = "insert"
def insert(): Unit = {
}
}
class MySQL {}
-反编译后的代码
8.4.8 特质中的抽象字段
特质中未被初始化的字段在具体的子类中必须被重写
8.4.9 特质构造顺序
-介绍
特质也是有构造器的,构造器中的内容由“字段的初始化”和一些其他语句构成
-第一种特质构造顺序(声明类的同时混入特质)
1) 调用当前类的超类构造器
2) 第一个特质的父特质构造器
3) 第一个特质构造器
4) 第二个特质构造器的父特质构造器,如果已经执行过就不再执行
5) 第二个特质构造器
6) ......重复4,5的步骤(如果有第3个,第4个特质)
7) 当前类构造器
-第二种特质构造顺序(在构建对象时,动态混入特质)
1) 调用当前类的超类构造器
2) 当前类构造器
3) 第一个特质构造器的父特质构造器
4) 第一个特质构造器
5) 第二个特质构造器的父特质构造器,如果已经执行过就不再执行
6) 第二个特质构造器
7) ......重复4,5的步骤(如果有第3个,第4个特质)
8) 当前类构造器
-两种方式对构造顺序的影响
1) 第一种方式实际是构建类对象,在混入特质时,该对象还没有创建
2) 第二种方式实际是构造匿名子类,可以理解成在混入特质时,对象已经创建了
-案例演示
object boke_demo01 {
def main(args: Array[String]): Unit = {
//这时FF是这样 形式 class FF extends EE with CC with DD
/*
调用当前类的超类构造器
第一个特质的父特质构造器
第一个特质构造器
第二个特质构造器的父特质构造器, 如果已经执行过,就不再执行
第二个特质构造器
.......重复4,5的步骤(如果有第3个,第4个特质)
当前类构造器 [案例演示]
*/
//1. E...
//2. A...
//3. B....
//4. C....
//5. D....
//6. F....
val ff1 = new FF()
println(ff1)
//这时我们是动态混入
/*
先创建 new KK 对象,然后再混入其它特质
调用当前类的超类构造器
当前类构造器
第一个特质构造器的父特质构造器
第一个特质构造器.
第二个