1. 程式人生 > >【圖文詳細 】Scala——特質 Trait

【圖文詳細 】Scala——特質 Trait

4、特質 Trait 

 

4.1、特質的定義 

Scala 和 Java 語言一樣,採用了很強的限制策略,避免了多繼承的問題。在 Java 語言中,只 允許繼承一個超類,該類可以實現多個介面,但 Java 介面有其自身的侷限性:介面中只能包括抽象方法,不能包含欄位、具體方法。Scala 語言利用 trait 解決了該問題,在 Scala 的 trait 中,它不但可以包括抽象方法還可以包含欄位和具體方法。

trait 的示例如下: 

package com.mazh.scala.day2.oop 
 
trait DAO{ 
  // 抽象欄位
 
  val id:Int 
  // 具體 欄位
 
  val name:String = "huangbo" 
// 帶 實現的具體方法
 
  def delete(id:String):Boolean = true 
// 定義一個抽象方法,注意不需要加 abstract, 加了 abstract反而會報錯
 
  def add(o:Any):Boolean 
  def update(o:Any):Int 
  def query(id:String):List[Any] 
}

 

4.2、Trait 的使用 

4.2.1、Trait 使用概述 

Java 中:

1、介面是一個特殊的抽象類

2、裡面所有的方法都是抽象方法。 
 
Scala 中:

1、 特質裡面的方法既可以實現,也可以不實現 那麼跟抽象類有什麼區別,兩點原因:

    1、優先使用特質。一個類擴充套件多個特質是很方便的,但卻只能擴充套件一個抽象類。

    2、如果你需要建構函式引數,使用抽象類。因為抽象類可以定義帶引數的建構函式, 而特質不行。例如,你不能說 trait t(i: Int) {},引數 i 是非法的。

2、抽象類,我們用的是 extends,我們只能單繼承,但是我們可以多實現

3、實現特質,如果沒有繼承其它類,那麼使用第一個特質使用 extends,後面的使用 with, 所以如果有考題說實現特質只能使用 with,這是不對的。 
 
Trait 的幾種不同使用方式

    1、當做 Java 介面使用的 trait,全是抽象欄位和抽象方法

    2、帶實現方法的 trait

    3、帶具體欄位的 trait

Traits 的底層實現就是採用的 Java 的抽象類

 

4.2.1、將特質作為介面使用 

Scala 中的 Triat 是一種特殊的概念 

首先我們可以將 Trait 作為介面來使用,此時的 Triat 就與 Java 中的介面非常類似 

在 Triat 中可以定義抽象方法,就與抽象類中的抽象方法一樣,不給出方法的具體實現 

在 Triat 中也可以定義具體方法,給出方法的具體實現 在 Triat 中可以定義具體欄位,

也可以定義抽象欄位 類可以使用 extends 關鍵字繼承 trait,注意,這裡不是 implement,而是 extends,

在 scala 中沒有 implement 的概念,無論繼承類還是 trait,統一都是 extends 類繼承 trait 後,

必須實現其中的抽象方法,實現時不需要使用 override 關鍵字

scala 不支援對類進行多繼承,但是支援多重繼承 trait,使用 with 關鍵字即可 

trait MySQLDAO{ 
  val id:Int 
  def add(o:Any):Boolean 
  def update(o:Any):Int 
  def query(id:String):List[Any] 
} 
 
// 如果有多個 trait的話,則使用 with關鍵字即可 
class DaoImpl extends MySQLDAO with Serializable{ 
  // 給父類中的抽象欄位賦值。
   override val id = 12 
  // 實現抽象方法
   def add(o:Any):Boolean = true 
  def update(o:Any):Int = 1 
  def query(id:String):List[Any] = List(1,2,3) 
}

 

4.2.2、在 Trait 中定義具體方法和屬性 

trait MySQLDAO{ 
 
  val id:Int 
  val name:String = "huangbo" 
 
  def add(o:Any):Boolean 
  def update(o:Any):Int 
  def query(id:String):List[Any] 
  def delete(id:Int) = {println("delete one record")} 
} 
 
// 如果有多個 trait的話,則使用 with關鍵字即可 
class DaoImpl extends MySQLDAO with Serializable{ 
 
  // 實現父類中的抽象方法,必須的
  def add(o:Any):Boolean=true 
  def update(o:Any):Int= 1 
  def query(id:String):List[Any]=List(1,2,3) 
 
  // 給父類中的抽象欄位賦值,必須的
   override val id = 12 
}

 

4.3.5、為例項物件混入 Trait 
有時我們可以在建立類的物件時,指定該物件混入某個 Trait,

這樣,就只有這個物件混入該 Trait 的方法,而類的其他物件則沒有 

package com.mazh.scala.day2.oop 
 
trait MyLogger { 
  def log(msg:String){} 
} 
trait Logger_A extends MyLogger{ 
  override def log(msg:String): Unit ={ 
    println("test:"+msg) 
  } 
} 
trait Logger_B extends MyLogger{ 
  override def log(msg:String): Unit ={ 
    println("log:"+msg) 
  } 
} 
class Person123(val name:String) extends Logger_A{ 
  def sayHello(): Unit ={ 
    println("Hi ,i'm name") 
    log("sayHello is invoked!") 
  } 
} 
object  MyLogger_Trait_Test{ 
  def main(args: Array[String]) { 
    val p1=new Person123("liudehua") 
    p1.sayHello() 
    val p2=new Person123("zhangxueyou") with Logger_B 
    p2.sayHello() 
  } 
} 

 

4.3.6、Trait 呼叫鏈 

Scala 中支援讓類繼承多個 Trait 後,依次呼叫多個 Trait 中的同一個方法,只要讓多個 Trait 的同一個方法中,在最後都執行 super.方法 即可 類中呼叫多個 Trait 中都有的這個方法時,首先會從最右邊的 Trait 的方法開始執行,然後依 次往左執行,形成一個呼叫鏈條 這種特性非常強大,其實就相當於設計模式中的責任鏈模式的一種具體實現依賴 

trait Handler { 
  def handler(data:String){} 
} 
trait Handler_A extends Handler{ 
  override def handler(data:String): Unit = { 
    println("Handler_A :"+data) 
    super.handler(data) 
  } 
} 
trait Handler_B extends Handler{ 
  override def handler(data:String): Unit = { 
    println("Handler_B :"+data) 
    super.handler(data) 
  } 
} 
trait Handler_C extends Handler{ 
  override def handler(data:String): Unit = { 
    println("Handler_C :"+data) 
 super.handler(data) 
  } 
} 
class  Person_TraitChain(val name:String) extends Handler_C with Handler_B with 
Handler_A{ 
  def sayHello={ 
    println("Hello "+name) 
    handler(name) 
  } 
} 
 
object TraitChain_Test{ 
  def main(args: Array[String]) { 
    val p=new Person_TraitChain("zhangxiaolong"); 
    p.sayHello 
  } 
} 

執行結果: 

Hello lixiaolong 
Handler_A :zhangxiaolong 
Handler_B :zhangxiaolong 
Handler_C :zhangxiaolong