Scala中trait相關知識和應用

1、trait基礎知識
1-1 將trait作為接口使用

//1、可以將trait作為接口來使用捣染,與Java類似
trait HelloTrait {
  //在trait中可以定義抽象方法鼻弧,只要不給出具體實現(xiàn)即可
  def sayHello(name:String)
}
trait MakeFriendsTrait{
  def makeFriends(p:Person)
}
//類可以使用extends關鍵字繼承trait唠梨,不是implements,
//在scala中無論繼承類還是trait很泊,統(tǒng)一使用extends
//scala不支持對類進行多繼承囱嫩,但支持多重繼承trait嫂侍,繼承第一個用extends儿捧,后邊的都用with
class Person(val name:String) extends HelloTrait with MakeFriendsTrait with Cloneable {
  //類繼承trait后,必須實現(xiàn)其中的抽象方法挑宠,實現(xiàn)時不需要使用override關鍵字
  def sayHello(name: String): Unit = println("Hello,"+name)
   def makeFriends(p: Person): Unit ={
     println("Hello,my name is "+name+",your name is "+p.name)
   }
}

//運行代碼:
val p1 = new Person("leo")
    val p2 = new Person("Jack")
    p1.sayHello("Jack")
    p1.makeFriends(p2)

運行結果:

Hello,Jack
Hello,my name is leo,your name is Jack

1-2 在trait中定義具體實現(xiàn)方法

trait Logger {
  //trait不僅可以定義抽象方法菲盾,也可以定義具體方法
  def log(msg:String)=println("logs:" + msg)
}
class Person(val name:String) extends HelloTrait
  with MakeFriendsTrait with Logger {
  //類繼承trait后,必須實現(xiàn)其中的抽象方法各淀,實現(xiàn)時不需要使用override關鍵字
  def sayHello(name: String): Unit = println("Hello,"+name)

  >def makeFriends(p: Person): Unit ={
    println("Hello,my name is "+name+",your name is "+p.name)
//此處調用trait實現(xiàn)的方法
    log("makeFriends method is invoked withparam p.name:"+p.name)
  }
}

運行結果:

Hello,my name is leo,your name is Jack
logs:makeFriends method is invoked withparam p.name:Jack

1-3 在trait中定義具體字段

//1懒鉴、可以將trait作為接口來使用,與Java類似
trait HelloTrait {
  //trait可以定義具體的field
  val count = 2
  //在trait中可以定義抽象方法碎浇,只要不給出具體實現(xiàn)即可
  def sayHello(name:String)
}
class Person(val name:String) extends HelloTrait {
  //類繼承trait后临谱,必須實現(xiàn)其中的抽象方法咆畏,實現(xiàn)時不需要使用override關鍵字
  def sayHello(name: String): Unit = println("Hello,"+name+",count="+count)
}
   val p1 = new Person("leo")
    p1.sayHello("Jack")

運行結果:

Hello,Jack,count=2

1-4 在trait中定義抽象字段

//1、可以將trait作為接口來使用吴裤,與Java類似
trait HelloTrait {
  //trait可以定義具體的field
  val count = 2
  //trait可以定義抽象的field
  val msg:String
  //trait可以定義具體實現(xiàn)方法
  def sayHello(name:String)=println(msg+","+name)
}
class Person(val name:String) extends HelloTrait{
  val msg: String = "Hello"
  def makeFriends(p: Person): Unit ={
    sayHello(p.name)
    println("Hello,my name is "+name+",your name is "+p.name)
  }
}
    val p1 = new Person("leo")
    val p2 = new Person("Jack")
    p1.makeFriends(p2)

運行結果:

Hello,Jack
Hello,my name is leo,your name is Jack

2旧找、trait高級知識
2-1 為實例對象混入trait

trait Logger {
  def log(msg:String){}
}
trait MyLogger extends Logger{
  //trait不僅可以定義抽象方法,也可以定義具體方法
  override def log(msg:String)=println("logs:" + msg)
}
class Person(val name:String) extends HelloTrait  with Logger {
  val msg: String = "Hello"
  //類繼承trait后麦牺,實現(xiàn)非抽象方法時钮蛛,必須要要使用override關鍵字
  override def sayHello(name: String): Unit = {
    println("Hello,"+name+",count="+count)
    log("sayHello method is invoked")
  }
}
val p1 = new Person("leo")
p1.sayHello("Jack")
val p2 = new Person("Jack") with MyLogger
p2.sayHello("leo")

運行結果:

Hello,Jack,count=2
Hello,leo,count=2
logs:sayHello method is invoked

2-2 trait調用鏈
1、scala支持讓類繼承多個trait剖膳,依次調用多個trait的同一個方法魏颓,只需要在多個trait的同一個方法中最后調用super方法即可
2、類中調用多個trait中都有的方法時吱晒,首先會從最右邊的方法開始執(zhí)行甸饱,然后依次往左執(zhí)行,形成一個調用鏈條
3仑濒、這種特性非常強大叹话,其實就相當于設計模式中的責任鏈模式的一種具體實現(xiàn)

trait Handler {
  def handle(data:String){}
}
trait DataValidHandler extends Handler{
  override def handle(data:String): Unit ={
    println("CHeckData "+data)
    super.handle(data)
  }
}
trait SignValidHandler extends Handler{
  override def handle(data:String): Unit ={
    println("CHeckSIgn "+data)
    super.handle(data)
  }
}
class MyHandler(val name:String)extends SignValidHandler with DataValidHandler {
  def sayHello = {
    println("Hello,"+name)
    handle(name)
  }
}
  val h1 = new MyHandler("Jack")
    h1.sayHello

運行結果:

Hello,Jack
CHeckData Jack
CHeckSIgn Jack

2-3 在trait中覆蓋抽象方法

trait Logger {
  def log(msg:String)
}
trait MyLogger extends Logger{
  //覆蓋時,如果使用了super.方法時墩瞳,無法通過編譯驼壶,因為super調用的是抽象方法,
  //此時子trait的方法還是被認為是抽象的喉酌,所以還需要加上abstract override修飾
  // method log in trait Logger is accessed from super.It may not be abstract unless it is overridden by a member declared `abstract' and `override'
//  override def log(msg:String){
//    println("logs:" + msg)
//    super.log(msg)
//  }
   abstract override def log(msg:String){
    println("logs:" + msg)
    super.log(msg)
  }
}

trait MySubLogger extends Logger {
  override def log(msg: String) {
    println("MySubLogger logs:" + msg)
  }
}
  
//類必須繼承實現(xiàn)了抽象方法的trait热凹,否則編譯報錯,報錯信息如下
//Error:(17, 7) class People needs to be a mixin, since method log in trait MyLogger of type (msg: String)Unit is marked `abstract' and `override', but no concrete implementation could be found in a base class
//class People  extends MyLogger{
class People  extends MySubLogger{
  var data:String = "test"
  def execLog = log(data)
}
object Main {
  def main(args: Array[String]): Unit = {
    var p = new People
    p.execLog
  }
}

2-4 混合使用trait的具體方法和抽象方法

trait Valid {
  //在trait中可以混合使用具體方法和抽象方法
  //可以讓具體方法依賴于抽象方法泪电,而通過具體類的方法來實現(xiàn)trait在抽象方法
  //這種trait其實就是設計模式中的模板設計模式的體現(xiàn)
  def getName:String
  def valid:Boolean={
    getName == "leo"
  }
}

class Person(val name:String) extends Valid{
  println(valid)
  def getName = name
}
 object  Main{
   def main(args: Array[String]): Unit = {
     val p = new Person("leo")
   }
 }

2-5 trait的構造機制

在scala中般妙,trait也是有構造方法的,就是不包含在任何方法的代碼
而繼承了trait類的構造機制如下:
1相速、父類的構造函數(shù)執(zhí)行碟渺;
2、trait的構造代碼執(zhí)行和蚪,多個trait從左到右止状,依次執(zhí)行烹棉;
3攒霹、構造trait時,會先構造父trait浆洗,如果多個trait繼承同一個父trait催束,則父trait只會構造一次;
4伏社、所有的trait構造完畢之后抠刺,子類的構造函數(shù)執(zhí)行

class Person1 {println("Person`s constructor")}
trait Logger1{println("Logger`s constructor")}
trait Mylogger extends Logger1{println("Mylogger`s constructor")}
trait Timerlogger extends Logger1{println("Timerlogger`s constructor")}
class Student1 extends Person1 with Mylogger with Timerlogger{
  println("Student`s constructor")
}
object  Main{
  def main(args: Array[String]): Unit = {
    val p = new Student1()
  }
}

運行結果如下:
Persons constructor Loggers constructor
Myloggers constructor Timerloggers constructor
Student`s constructor

2-6 trait字段的初始化
在scala中塔淤,trait是沒有接收參數(shù)的構造函數(shù)的,這是trait與class的唯一區(qū)別速妖,但是如果需要trait對field進行初始化高蜂,只能使用scala中非常特殊的一種高級特性,--提前定義

trait sayHello{
  val msg:String
  println(msg.toString)
}

class Person extends sayHello{
   val msg: String = "hello"
}

直接構造罕容,會先構造父類备恤,msg還沒初始化,就打印锦秒,會報空指針錯誤

val p = new Person    //java.lang.NullPointerException

下面幾種方式則不會出錯:
創(chuàng)建實例的時候露泊,動態(tài)混入屬性,并賦值

//重新定義沒有屬性的類
class Person 
//提前賦值
    val p = new {
      val msg:String = "init"
    } with Person with sayHello

還有一種寫法

class Person extends {
  val msg:String = "init"
} with sayHello
 val p = new Person

還有一種寫法:

trait sayHello{
  lazy val msg:String = null
  println(msg.toString)
}

class Person extends sayHello{
 override lazy val msg:String = "init"
}

object Main{
  def main(args: Array[String]): Unit = {
    val p = new Person
  }
}

2-7 讓trait繼承類
在scala中旅择,trait也可以繼承class惭笑,此時class就會成為所有繼承該trait的類的父類

class MYUtil {
  def printMessage(msg:String) = println(msg)
}
trait Logge extends MYUtil{
  def log(msg:String)= printMessage(msg)
}
class Person(val name:String)extends Logge{
  def sayHello: Unit ={
    log("Hi,I'm "+name)
    printMessage("Hi,I'm "+name)
  }
}

object Main{
  def main(args: Array[String]): Unit = {
    val p = new Person("leo")
    p.sayHello
  }
}
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市生真,隨后出現(xiàn)的幾起案子沉噩,更是在濱河造成了極大的恐慌,老刑警劉巖柱蟀,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屁擅,死亡現(xiàn)場離奇詭異,居然都是意外死亡产弹,警方通過查閱死者的電腦和手機派歌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痰哨,“玉大人胶果,你說我怎么就攤上這事〗锔” “怎么了早抠?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長撬讽。 經(jīng)常有香客問我蕊连,道長,這世上最難降的妖魔是什么游昼? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任甘苍,我火速辦了婚禮,結果婚禮上烘豌,老公的妹妹穿的比我還像新娘载庭。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布囚聚。 她就那樣靜靜地躺著靖榕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪顽铸。 梳的紋絲不亂的頭發(fā)上茁计,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天,我揣著相機與錄音谓松,去河邊找鬼簸淀。 笑死,一個胖子當著我的面吹牛毒返,可吹牛的內(nèi)容都是我干的租幕。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼拧簸,長吁一口氣:“原來是場噩夢啊……” “哼劲绪!你這毒婦竟也來了?” 一聲冷哼從身側響起盆赤,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤贾富,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后牺六,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颤枪,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年淑际,在試婚紗的時候發(fā)現(xiàn)自己被綠了畏纲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡春缕,死狀恐怖盗胀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锄贼,我是刑警寧澤票灰,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站宅荤,受9級特大地震影響屑迂,放射性物質發(fā)生泄漏。R本人自食惡果不足惜冯键,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一惹盼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧琼了,春花似錦逻锐、人聲如沸夫晌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至所袁,卻和暖如春盏档,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背燥爷。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工蜈亩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人前翎。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓稚配,卻偏偏與公主長得像,于是被迫代替她去往敵國和親港华。 傳聞我的和親對象是個殘疾皇子道川,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容