標籤:

Scala快速入門-8-特質

知識點

  • Scala和Java一樣不允許類繼承多個超類,特質解決這一局限性
  • 類可以實現任意數量的特質
  • 當將多個特質疊加在一起時,順序很重要,其方法先被執行的特質排在更後面
  • Scala特質可以提供方法和欄位的實現
  • 特質要求實現它們的類具備特定的欄位、方法或超類
  • 特質可以同時擁有抽象方法和具體方法,而類可以實現多個特質

當做介面使用的特質

  • Scala特質完全可以像Java的介面一樣,使用關鍵字 trait
  • 不需要將方法聲明為abstract,特質中未被實現的方法默認就是抽象的
  • 在子類中重寫特質的抽象方法不需要用 override 關鍵字

package com.gemantic.base/** * @author Yezhiwei * @date 18/1/6 */object TraitLearn { def main(args: Array[String]): Unit = { val logger = new ConsoleLogger logger.log("console log message...") }}trait Logger { def log(msg: String)}class ConsoleLogger extends Logger { override def log(msg: String): Unit = println(msg)}package com.gemantic.base /** * @author Yezhiwei * @date 18/1/6 */ object TraitLearn { def main(args: Array[String]): Unit = { val logger = new ConsoleLogger logger.log("console log message...") } } trait Logger { def log(msg: String) } class ConsoleLogger extends Logger { override def log(msg: String): Unit = println(msg) }

說明:

子類實現特質,用 extends 而不是 implements

不需要寫 override

如果需要多個特質,可以用with關鍵字來添加額外的特質,如下代碼

class ConsoleLogger extends Logger with Serializable { override def log(msg: String): Unit = println(msg)}

帶有具體實現的特質

  • 在Scala的特質中的方法並不需要一定是抽象的
  • 子類從特質得到了一個具體的log方法實現

trait ConsoleLoggerImp { def log(msg: String) {println(msg)}}class AccountAction extends Account with ConsoleLoggerImp { def withdraw(amount: Double): Unit = { if (amount > nowBalance) { log("insufficient funds") } else { log("enough funds") } }}object TraitLearn { def main(args: Array[String]): Unit = { // 當做介面使用的特質 val logger = new ConsoleLogger logger.log("console log message...") // 帶有具體實現的特質 val accountAction = new AccountAction accountAction.withdraw(1000) }}

帶有特質的對象

  • 在構造單個對象時,可以為它添加特質
  • 在定義子類時可以使用不做任何實現的特質,在構造具體對象的時候混入一個更合適的實現
  • 特質中重寫抽象方法,必須在方法上使用 abstract 及 override

// 有默認實現,但是什麼也沒有做trait Logged { def log(msg: String) {}}trait FileLogged extends Logged { override def log(msg: String): Unit = println("saving file : " + msg)}class AccountAction extends Account with Logged { def withdraw(amount: Double): Unit = { if (amount > nowBalance) { log("insufficient funds") } else { log("enough funds") } }}object TraitLearn { def main(args: Array[String]): Unit = { // 帶有特質的對象,可以混入不同的日誌 val accountActionLogger = new AccountAction with FileLogged accountActionLogger.withdraw(1000) }}// 運行輸出結果saving file : insufficient funds

疊加在一起的特質

  • 可以為類或對象添加多個互相調用的特質,從最後一個開始被處理

// 為日誌增加時間戳trait TimestampLogged extends Logged { override def log(msg: String): Unit = super.log(new java.util.Date() + " " + msg)}// 如果日誌內容長度超過10,截斷trait ShortLogged extends Logged { override def log(msg: String): Unit = super.log(if (msg.length <= 10) msg else msg.substring(0, 10) + "...")}object TraitLearn { def main(args: Array[String]): Unit = { // 帶有特質的對象 val accountActionLogger = new AccountAction with FileLogged with TimestampLogged with ShortLogged accountActionLogger.withdraw(1000) val accountActionLogger1 = new AccountAction with FileLogged with ShortLogged with TimestampLogged accountActionLogger1.withdraw(1000) }}// 輸出結果為saving file : Sat Jan 06 12:38:07 CST 2018 insufficie...saving file : Sat Jan 06...

  • 注意上面的特質調用順序及log方法每一個都將修改過的消息傳遞給supper.log

特質構造順序

  • 和類一樣,特質也可以有構造器,由欄位的初始化和其他特質體中的語句構成
  • 構造器執行順序

首先調用超類的構造器

特質構造器在超類構造器之後、類構造器之前執行

特質由左到右被構造

每個物質當中,父特質先被構造

如果多個特質共有一個父特質,而那個父特質已經被構造,則不會再次構造

所有的特質構造完畢,子類被構造

  • 示例

class AccountAction extends Account with FileLogged with ShortLogged { ...}

構造器執行順序如下

超類 Account

Logged ,第一個特質的父特質

FileLogged 第一個特質

ShortLogged 第二個特質,它的父特質Logged已被構造

AccountAction 子類

敬請期待下一篇<高階函數>~

作者:Yezhiwei

鏈接: Scala快速入門-8-特質Scala快速入門-7-繼承 | Yezhiwei Blog

聲明:本文來源於網路,版權歸作者所有,轉載請註明,若有什麼問題,請聯繫我們,謝謝!

推薦閱讀:

Scala快速入門-5-類定義
#Scala#一個函數的分析,以及生活路上
scala 庫是如何做到並行的?
為什麼 Scala 不建議用 return?
國內有哪些 Scala 大牛?

TAG:Scala |