基礎知識
-
Trait(特征):是一種特殊的概念,相當於 Java 的接口,實際上它比接口還功能強大,它還可以定義屬性和方法的實現
- Trait的定義:定義的方式和定義類的方式相同
-
scala不支持對類進行多繼承,但是支持多重繼承trait,使用with關鍵字即可,解決類的單繼承問題
-
類繼承trait后,必須實現其中的抽象方法和抽象字段
-
trait也可以繼承自class,此時這個class就會成為所有繼承該trait的類的父類
抽象方法和抽象字段
- 在triat中可以定義抽象方法,定義的抽象方法可以直接在trait中引用
- Triat可以定義抽象field,定義的抽象字段可以在trait中直接引用,此時抽象字段有默認值
object test11 { trait Sayhello{ val name :String //抽象字段 println(name) //調用抽象字段 def sayhello(name:String)=println(s"hello,$name") //具體方法調用抽象字段 } trait MakeFriends{ def makeFrinds(str:String) //抽象方法 def log(msg: String) {} //{}表示不是抽象方法 } class Person(val name:String) extends Sayhello with MakeFriends{ //with實現多繼承 def makeFrinds(str:String)=print(s"可以交個朋友嗎?$str") //實現MakeFriends中的抽象方法 } def main(args: Array[String]): Unit = { val person=new Person("Wei") person.sayhello("Tom") person.makeFrinds("Tom") } }
具體方法和具體字段
- 就像普通類中的具體方法和具體字段一樣
object test12{ trait Person { val age: Int = 2 def eat(food: String) = println(s"吃 $food") } class Student(val name: String) extends Person {} def main(args: Array[String]): Unit = { val person = new Student("tom") println(person.age) person.eat("橘子") } }
高級知識
實例對象繼承trait
- 創建對象的時候只需要某個實例對象繼承trait,而不需要類中的其他對象繼承trait
- 對象動態繼承的trait會覆蓋對象實現類的成員(Man覆蓋了Person方法)
object test21{ trait Person { def eat(food: String) {println("不喜歡吃"+food)} } trait Man extends Person { override def eat(food: String){println("喜歡吃"+food)} } class Teacher(val name: String) extends Person { def sayHello { println("你好,我是" + name) eat("水果") } } def main(args: Array[String]): Unit = { val p1 = new Teacher("wiki") p1.sayHello println("\t") val p2 = new Teacher("jack") with Man p2.sayHello } }
調用鏈
- 類繼承traitA,traitA繼承traitB,traitB繼承traitC,traitC繼承traitD,如果要同時調用trait[A-D]中相同的方法fun1,只要將只需要將super.fun1放入到fun1中即可,形成一個調用鏈條
object test22 { trait KeyWord { def logger(data: String): Unit = { println("第一次密碼是:" + data) } } trait KeyWord1 extends KeyWord { override def logger(data: String): Unit = { println("第二次密碼是:" + data) super.logger(data) } } trait KeyWord2 extends KeyWord1 { override def logger(data: String): Unit = { println("第三次密碼是:" + data) super.logger(data) } } class KeyWord3 extends KeyWord2 { def log(data: String): Unit = { logger(data) } } def main(args: Array[String]): Unit = { val s = new KeyWord3 s.log("car360") } } /** * 輸出結果: * 第三次密碼是:car360 * 第二次密碼是:car360 * 第一次密碼是:car360 */
abstract override
- trait可以直接引用抽象方法,但是子類中不可以直接引用父類的抽象方法,需要引用必須用abstract override修飾
object test23{ trait Person { def play(str: String) def eat(str: String) { play(str) } } trait Teacher extends Person { abstract override def play(str: String) { super.play(str) } def eat(str: String) { super.eat(str) } //會報錯 def say(str: String) { super.play(str) } } }
構造機制
- trait也有構造函數
- 繼承了trait的類的構造機制如下:
- 父類的構造函數先執行
- 類繼承的traitA如果有父traitB,父traitB的構造代碼先執行(多個trait繼承同一個父trait,則父trait只會構造一次)
- trait的構造代碼執行,多個trait從左到右依次執行
- 子類的構造函數執行
object test24{ class Person { println("Person's constructor!") } trait Number { println("Number's constructor!") } trait First extends Number { println("First's constructor!") } trait Second extends Number { println("Second's constructor!") } class Student extends Person with First with Second { println("Student's constructor!") } def main(args: Array[String]): Unit = { val stu = new Student } } //運行結果: //Person's constructor! //Number's constructor! //First's constructor! //Second's constructor! //Student's constructor!
字段的初始化
- trait沒有接收參數的構造函數
- trait中的抽象字段都有默認值
- 提前定義:在調用trait的構造函數時候重寫了字段值
- lazy:不能用於抽象字段,只能用於具體字段
方法一:提前定義
object test25 { trait Person{ val num:String println(num) println(num.toInt+123) } class Student(number: String) extends Person{ val num:String=number print("the new num is "+num) } def main(args: Array[String]): Unit = { // val s= new Person("123") //會報錯因為他會先執行trait的println num此時是null,這時就需要用到提前定義了 val p = new { override val num: String = "123" } with Student("456") //注意:傳入的參數是123而不是456 } }
方法二:用lazy
trait Person{ lazy val num:String=null //注意lazy不能用於抽象字段,只能用與具體字段 println(num.toInt+123) } class Student (number: String) extends Person{ override lazy val num:String=number print("the new num is "+num) } object test { def main(args: Array[String]): Unit = { val p = new Student("123") } }