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 { ...}
構造器執行順序如下
超類 AccountLogged ,第一個特質的父特質FileLogged 第一個特質ShortLogged 第二個特質,它的父特質Logged已被構造
AccountAction 子類
敬請期待下一篇<高階函數>~
作者:Yezhiwei
鏈接: Scala快速入門-8-特質Scala快速入門-7-繼承 | Yezhiwei Blog聲明:本文來源於網路,版權歸作者所有,轉載請註明,若有什麼問題,請聯繫我們,謝謝!
推薦閱讀:
※Scala快速入門-5-類定義
※#Scala#一個函數的分析,以及生活路上
※scala 庫是如何做到並行的?
※為什麼 Scala 不建議用 return?
※國內有哪些 Scala 大牛?
TAG:Scala |