scala學習之特質 trait

2022-09-10 21:24:20 字數 4006 閱讀 7581

特質,很像j**a中的介面,但是又有些不同,比如實現方法,當然j**a8也可以在介面中實現乙個方法了,但是只能定義乙個default方法。

當做介面使用

//特質

trait

logger

trait

consolelogger

extends

logger //不需要寫 overrride

//在重寫 特質的抽象方法是不需要寫 overrride關鍵字

//如果需要的特質不止乙個,可以使用with連線

//特質中的方法並不一定是抽象的

def write(msg:string)

}

含有具體實現

例子**於 快學scala

先定義這麼乙個trait

trait

logged

}

寫乙個class繼承它

class

s**ingaccount

extends

account

with

logged

}

從**上看,在logged 中,我們並沒有實現此方法,所以這裡的log是無意義的。

但是在scala中並非如此。

trait

consolelogged

extends

logged

}

定義一trait繼承logged,並實現log方法,然後鑼鼓一響,好戲開場

object

testtrait

extends

val acct = new s**ingaccount with consolelogged

acct.withdraw(2.2)

}

你會控制台有日誌列印。

下面看下多個trait的執行順序,是一件非常有意思的事情,首先寫幾個trait,**如下:

trait

consolelogged

extends

logged

}

trait

timestamplogger

extends

logged

}

trait

shortlogger

extends

logged

}

測試:

val acct = new s**ingaccount with consolelogged

acct.withdraw(3.2)

val acct1 = new s**ingaccount with consolelogged with timestamplogger with shortlogger

acct1.withdraw(2.2)

val acct2=new s**ingaccount with timestamplogger with consolelogged with shortlogger

acct2.withdraw(2.5)

val acct3=new s**ingaccount with consolelogged with shortlogger with timestamplogger

acct3.withdraw(2.5)

val acct4=new s**ingaccount with timestamplogger with shortlogger with consolelogged

acct4.withdraw(2.5)

輸出如下:

console=>s**ingaccount print =>

s**ingaccount p...short.print at.thu aug 13

17:54:17 cst 2015

console=>s**ingaccount p...short

s**ingaccount print =>.print at.thu aug 13

17:54:17 cst 2015

console=>s**ingaccount print =>

從列印結果分析看,如果trait是從左到右開始執行,那麼第三條和第五條沒有輸出是無法解釋的;那麼如果從右開始執行呢,可以看到第二條輸出,先執行shortlogger,呼叫super.log,執行timestamplogger,那麼consolelogged似乎沒有被呼叫;以此解釋第三條輸出也是說的通的,而timestamplogger沒有被執行,那麼第四條資料呢,只是執行了timestamplogger,同理第五條也是如此,如果沒有super,似乎前面的trait中的方法不會被呼叫,但是,如果我在timestamplogger如此做的話,需要打上abstract標籤,輸出結果和上面相同,這裡有些疑問,暫且存疑。

在特質中宣告字段

在trait中欄位宣告可以是具體的,也可以是抽象的,如果在字段宣告時初始化,就是具體的。如果有子類繼承吃trait,改字段在jvm中,實際上是屬於子類的字段,和子類字段放在一起。

宣告抽象字段

trait

shortlogger

extends

logged

}

需要在子類中對其初始化,例如:

class

s**ingaccount

extends

account

with

shortlogger

override

val maxlength: int = 15

}

也可以如此:

val acct1 = new s**ingaccount with consolelogged with timestamplogger with shortlogger
特質的構造順序

trait是有構造順序的,初始化乙個類,構造順序如下:

先呼叫超類的構造方法

trait構造方法在超類構造方法之後和類的構造方法之前執行

trait由左到右被構造(待驗證)

在trait中,父trait首先被構造

如果多個trait共有乙個父trait,而父trait已經被構造,則不會父trait不會再被構造

所有的trait被構造完畢,類被構造

new s**ingaccount with consolelogged  with timestamplogger with shortlogger
根據《快學scala》中介紹的構造順數,線性化相反的方向,串接並去掉重複選項,右側勝出

以上面的為例子:

s**ingaccount >>shortlogger>>timestamplogger >>consolelogged >>logged>>account

但是輸出結果:

s**ingaccount p...short

.print at.fri aug 14

17:17:41 cst 2015

但是從輸出結果上分析,少了consolelogged 的輸出結果,至於為什麼,恕在下才疏學淺,還沒有找到結果。

scala執行時需要jvm的,但是jvm只支援單一繼承。那麼scala的trait在jvm中是怎麼被翻譯的呢?

如果scala只有抽象方法時,trait被翻譯成介面,如果trait有具體的方法實現,scala會建立乙個伴生類,該伴生類用靜態方法存放特質的方法,這些伴生類中不會有任何字段。特質中的字段會對應到介面中抽象的setter和getter方法。如果trait繼承自某個超類,伴生類不會繼承改超類,該超類會被任何實現該特質的類繼承。

Scala 系列 特質 Trait

本文主要對scala中特質的概念與使用進行介紹 特質是scala裡面 復用的基礎單元。與 python 不同,python 子類可以繼承自多個父類,而 scala 不允許乙個類從從個超類繼承,只能繼承唯一的超類。但是 scala 允許乙個類混入任意數量的特質,混入就是指類使用了特質提供的方法。那麼特...

Scala基礎 7 特質(Trait)

特質定義使用關鍵字trait trait carid上面定義了乙個trait,裡面包含乙個抽象欄位id和抽象方法currentid。注意,抽象方法不需要使用abstract關鍵字,特質中沒有方法體的方法,預設就是抽象方法。trait定義好之後,就可以使用extends或with關鍵字將trait混入...

scala學習(十五) trait

下面是乙個trait的簡單例子,裡面包含的trait的基本用法,trait的繼承 trait logger def warn msg string trait logger2 trait logger3 import scala.reflect.class dog extends logger wi...