1.特质中可以加入抽象方法和具体方法,可以直接当作Java下的接口使用。
2.类可以直接添加特质,使用extends关键字,多个特质使用with相连
trait Logger{
def log(msg:String)
}
class ConsoleLogger extends Logger{
def log(msg:String){println(msg)}
}
3.定义对象时可以直接动态混入特质。(使用with关键字)
trait Logger{
def log(msg:String,key:Int=3)
}
class A{
}
val a:A=new A with Logger {
override def log(msg: String, key: Int): Unit = ???
}
4.特质的叠加(难点!)
构建对象的同时如果混入多个特质,称之为叠加特质。
特质的声明顺序从左到右 ,方法执行顺序从右到左。
package com.atguigu.chapter08.mixin
//看看混入多个特质的特点(叠加特质)
object AddTraits {
def main(args: Array[String]): Unit = {
//说明
//1. 创建 MySQL4实例时,动态的混入 DB4 和 File4
//研究第一个问题,当我们创建一个动态混入对象时,其顺序是怎样的
//总结一句话
//Scala在叠加特质的时候,会首先从后面的特质开始执行(即从左到右)
//1.Operate4...
//2.Data4
//3.DB4
//4.File4
val mysql = new MySQL4 with DB4 with File4
println(mysql)
//研究第2个问题,当我们执行一个动态混入对象的方法,其执行顺序是怎样的
//顺序是,(1)从右到左开始执行 , (2)当执行到super时,是指的左边的特质 (3) 如果左边没有特质了,则super就是父特质
//1. 向文件"
//2. 向数据库
//3. 插入数据 100
mysql.insert(100)
println("===================================================")
//练习题
val mySQL4 = new MySQL4 with File4 with DB4
mySQL4.insert(999)
//构建顺序
//1.Operate4...
//2.Data4
//3.File4
//4.DB4
//执行顺序
//1. 向数据库
//2. 向文件
//3. 插入数据 = 999
}
}
trait Operate4 { //特点
println("Operate4...")
def insert(id: Int) //抽象方法
}
trait Data4 extends Operate4 { //特质,继承了Operate4
println("Data4")
override def insert(id: Int): Unit = { //实现/重写 Operate4 的insert
println("插入数据 = " + id)
}
}
trait DB4 extends Data4 { //特质,继承 Data4
println("DB4")
override def insert(id: Int): Unit = { // 重写 Data4 的insert
println("向数据库")
super.insert(id)
}
}
trait File4 extends Data4 { //特质,继承 Data4
println("File4")
override def insert(id: Int): Unit = { // 重写 Data4 的insert
println("向文件")
//super.insert(id) //调用了insert方法(难点),这里super在动态混入时,不一定是父类
//如果我们希望直接调用Data4的insert方法,可以指定,如下
//说明:super[?] ?的类型,必须是当前的特质的直接父特质(超类)
super[Data4].insert(id)
}
}
class MySQL4 {} //普通类
5.特质中重写抽象方法
如果超类特质的方法是抽象的,不能在子类中写super.超类抽象方法,很好理解,但在方法前加入关键字abstract override便可以正常使用。
6.富接口:带有抽象方法和具体方法的特质
7.特质中的字段:可以有具体的,也可以有抽象的,但抽象的在混入时需要实现。
8.特质的构造顺序:
1)声明类的同时混入特质
1.调用当前类的超类构造器;2.第一个特质的父构造器;3.第一个特质的构造器;4.第二个特质构造器的父特质构造器,如果已经执行过,就不再执行;5.第二个特质构造器;6.重复4,5步骤(如果有第3个,第4个特质);7.当前类构造器
2)构建对象时动态混入特质
1.调用当前类的超类构造器;2.当前类构造器;3第一个特质构造器的父特质构造器;4.第一个特质构造器;5.第二个特质构造器的父特质构造器, 如果已经执行过,就不再执行 6.第二个特质构造器;7........重复5,6的步骤(如果有第3个,第4个特质);8.当前类构造器
9.拓展类的特质
特质可以继承类,以用来拓展该特质的一些功能。
所有混入该特质的类,会自动成为哪个特质所继承的超类的子类。
如果混入该特质的类,已经继承了另一个类(A类),则要求A类时特质超类的子类,否则就会出现了多继承现象,发生错误。
10.自身类型。
1)不拓展类的情况下,限制混入该特质类的类型
2)可以使用类中的方法
package com.atguigu.chapter08.selftype
object SelfTypeDemo {
def main(args: Array[String]): Unit = {
}
}
//Logger就是自身类型特质,当这里做了自身类型后,那么
// trait Logger extends Exception,要求混入该特质的类也是 Exception子类
trait Logger {
// 明确告诉编译器,我就是Exception,如果没有这句话,下面的getMessage不能调用
this: Exception =>
def log(): Unit ={
// 既然我就是Exception, 那么就可以调用其中的方法
println(getMessage)
}
}
//class Console extends Logger {} //对吗? 错误
class Console extends Exception with Logger {}//对吗?