您好,登錄后才能下訂單哦!
本篇內容主要講解“Scala混入多重繼承、類型層次和集合怎么實現”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Scala混入多重繼承、類型層次和集合怎么實現”吧!
用特征來實現混入(mix-in)式的多重繼承
Scala里相當于Java接口的是特征(Trait)。Trait的英文意思是特質和性狀(本文稱其為特征),實際上他比接口還功能強大。與接口不同的是,它還可以定義屬性和方法的實現。Scala中特征被用于服務于單一目的功能模塊的模塊化中。通過混合這種特征(模塊)群來實現各種應用程序的功能要求,Scala也是按照這個構想來設計的。
一般情況下Scala的類只能夠繼承單一父類,但是如果是特征的話就可以繼承多個,從結果來看就是實現了多重繼承。這可以被認為是同Ruby模塊基本相同的功能。就看一下下面的例子吧。為了辨認方便,此后的特征名稱前都加上前綴字母T。特征既可以繼承類也可以繼承其他特征。
class Person ; //實驗用的空類,如果使用了上一次的Person類,則下面的 //PianoplayingTeacher類就需要構造參數了 trait TTeacher extends Person { def teach //虛方法,沒有實現 } trait TPianoPlayer extends Person { def playPiano = {println("I’m playing piano. ")} //實方法,已實現 } class PianoplayingTeacher extends Person with TTeacher with TPianoPlayer { def teach = {println("I’m teaching students. ")} //定義虛方法的實現 }
如上所示,可以連著多個with語句來混合多個特征到一個類中。***個被繼承源用extends,第二個以后的就用with語句。正如大家所知道的,可以生成實例的是非抽象(abstract)的類。另外請注意一下從特征是不可以直接創建實例的。
那么就實際運行一下吧。
scala> val t1 = new PianoplayingTeacher t1: PianoplayingTeacher = PianoplayingTeacher@170a650 scala> t1.playPiano I’m playing piano. scala> t1.teach I’m teaching students.
實際上如下所示,可以在創建對象時才將特征各自的特點賦予對象。
scala> val tanakaTaro = new Person with TTeacher with TPianoPlayer { | def teach = {println("I'm teaching students.")} } tanakaTaro: Person with TTeacher with TPianoPlayer = $anon$1@5bcd91 scala> tanakaTaro playPiano I’m playing piano. scala> tanakaTaro teach I'm teaching students.
用特征來方便地實現面向方面的編程
充分利用特征的功能之后,就能方便地實現現今流行的面向方面編程(AOP)了。
首先,用特征來聲明表示基本動作方法的模塊Taction。
trait TAction { def doAction }
接著作為被加入的方面,定義一下加入了前置處理和后置處理的特征TBeforeAfter。
trait TBeforeAfter extends TAction { abstract override def doAction { println("/entry before-action") //doAction的前置處理 super.doAction // 調用原來的處理 println("/exit after-action") //doAction的后置處理 } }
通過上面的abstract override def doAction {}語句來覆蓋虛方法。具體來說這當中的super.doAction是關鍵,他調用了TAction的doAction方法。其原理是,由于doAction是虛方法,所以實際被執行的是被調用的實體類中所定義的方法。
那么將實際執行的實體類RealAction作為TAction的子類來實現吧。
class RealAction extends TAction { def doAction = { println("** real action done!! **") } }
接著就執行一下。
scala> val act1 = new RealAction with TBeforeAfter act1: RealAction with TBeforeAfter = $anon$1@3bce70 scala> act1.doAction /entry before-action ** real action done!! ** /exit after-action
僅僅這樣還不好玩,接著為他定義一下別的方面,然后將這些方面加入到同一對象的方法中。接著定義一個將源方法執行兩遍的方面。
trait TTwiceAction extends TAction { abstract override def doAction { for ( i <- 1 to 2 ) { // 循環執行源方法的方面 super.doAction // 調用源方法doAction println( " ==> No." + i ) } } }
下面,將TBeforeAfter和TtwiceAction混合在一起后執行一下。
scala> val act2 = new RealAction with TBeforeAfter with TTwiceAction act2: RealAction with TBeforeAfter with TTwiceAction = $anon$1@1fcbac1 scala> act2.doAction /entry before-action ** real action done!! ** /exit after-action ==> No.1 /entry before-action ** real action done!! ** /exit after-action ==> No.2
伴隨著原來方法的before/after動作一起各自執行了兩次。接著將混入順序顛倒后再試一下。
scala> val act3 = new RealAction with TTwiceAction with TBeforeAfter act3: RealAction with TTwiceAction with TBeforeAfter = $anon$1@6af790 scala> act3.doAction /entry before-action ** real action done!! ** ==> No.1 ** real action done!! ** ==> No.2 /exit after-action
這樣執行后,原來的實現方法被循環執行了兩次,但是before/after則在循環以外整體只執行了一次。這是根據with語句定義的順序來執行的,知道了這原理之后也就沒有什么奇怪的了。Scala特性的如此混入順序是和AspectJ的方面以及Spring的interceptor相同的。
這樣不僅是before和after動作,只要更改了特征的實現就可以將各種方面動態地加入到原來的對象中去了,讀者自己也可以嘗試一下各種其他情況。
在Java中通過Decorator或Template Method模式來想盡辦法實現的功能,在Scala中只要通過特征就可以輕松到手了。從這還可以延展開來,通過在原來的方法中插入掛鉤的方法,即所謂的攔截者式面向方面的方法,就可以輕松地將各個方面通過特征來組件化了。
請讀者如果想起Scala是怎樣的強類型和靜態化語言的話,那么就能夠明白通過特征來加入新功能的特
點給他帶來了多大的靈活性。
Scala的類型體系(基本類型)
Scala中可使用的基本數據都以類的形式被定義了,所以基本類型與用戶定義類型可以認為是沒有區別的。雖然這么說,Scala還是提供了與Java的數據類型相對應的類定義群(圖 4-1)。這絕不是包裝類,在編譯后他們將被映射為Java的字節碼,所以性能上是絕對沒有問題的。
圖 4-1與Scala基本類型相對應的類群
如下例程序所示,對于整數對象7可以響應各種消息(方法)。既可以執行toString方法來轉換成字符串,又可以使用to這個執行Int => Range的方法。附帶說一下,7 to 20相當于7.to(20),該方法的執行結果是Range(7,8, 9, … 19, 20)。對于該范圍對象適用了foreach( (i)=>print(i) ),print _則與一個參數的匿名函數(i) => print(i)相當。
scala> 7.toString res2: java.lang.String = 7 scala> 7 to 20 foreach( print _ ) 7891011121314151617181920
實際上,Scala在編譯器自動引入的Predef單例對象中定義了為了兼容Java基礎類型所存在的類型別名。例如boolean, char, byte, short, int, long, float, double被定義了,這些別名實際上是引用了Scala.Boolean,Scala.Char,Scala.Byte等Scala的類。可能的話,為了提高“Scala中說所有數據都是對象”這種意識,建議盡量一開始就使用Int、Boolean、Float等原來的類名。
不過,在Scala種并沒有類型轉換操作符,而是在所有類的基類Any中定義了具有同等功能的方法asInstanceOf[X]。用這方法就可以把類型轉換為X了。Any類中同時還定義了相當于instanceof操作符的isInstanceOf[X]方法。
圖 4-2Scala類層次的基本結構
特別是該類層次中Iterable下的集類型在函數式編程中大顯身手。其中的可變(mutable)與非可變(immutable)兩大系列的類層次基本上呈現出鏡像關系,可以充分發揮出函數式語言功能的當然就是非可變集類型群了。
到此,相信大家對“Scala混入多重繼承、類型層次和集合怎么實現”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。