Scala中的巢狀類
在Scala中,你幾乎可以在任何語法結構中內嵌任何語法結構。如在類中可以再定義一個類,這樣的類是巢狀類,其他語法結構也是一樣。巢狀類類似於Java中的內部類。
對於Scala來說,成員內部類和靜態內部類存在不同的位置中,成員內部類正常的存在於類的成員位置中,而靜態內部類因為是靜態性質的,所以宣告在類對應的伴隨物件中。
使用的案例如下:
class ScalaOuterClass { class ScalaInnerClass { //成員內部類 } } object ScalaOuterClass { //伴生物件 class ScalaStaticInnerClass { //靜態內部類 } }
1、建立內部類的方法
object ScalaInnerClass { def main(args: Array[String]): Unit = { //建立兩個外部類的例項 val outer1 : ScalaOuterClass = new ScalaOuterClass(); val outer2 : ScalaOuterClass = new ScalaOuterClass(); //在scala中建立成員內部類的語法是:new 物件.內部類 //預設情況下,內部類例項和外部物件關聯 val inner1 = newouter1.ScalaInnerClass val inner2 = new outer2.ScalaInnerClass //建立靜態內部類例項 val staticInnerClass = new ScalaOuterClass.ScalaStaticInnerClass } }
2、訪問外部類屬性的方法
(1)外部類名.this.屬性名
可以通過外部類物件訪問外部類的屬性
class ScalaOuterClass { var name:String = "scott" private var sal:Double = 1.2 classScalaInnerClass { //成員內部類 def info()={ // 內部類如果想要訪問外部類的屬性,可以通過外部類物件訪問。 // 即訪問方式:外部類名.this.屬性名 println("name="+ScalaOuterClass.this.name+"age="+ ScalaOuterClass.this.sal) } } } object ScalaOuterClass { //伴生物件 class ScalaStaticInnerClass { //靜態內部類 } }
外部類名.this相當於是這個外部類的一個例項,然後通過“外部類名.this”這個例項物件去訪問屬性
(2)外部類名別名.屬性名
內部類如果想要訪問外部類的屬性,也可以通過外部類別名訪問(推薦)
class ScalaOuterClass { myOuter => //這樣寫,你可以理解成這樣寫,myOuter就是代表外部類的一個物件. class ScalaInnerClass { //成員內部類 def info() = { println("name = " + ScalaOuterClass.this.name + " age =" + ScalaOuterClass.this.sal) println("-----------------------------------") println("name = " + myOuter.name + " age =" + myOuter.sal) }} // 當給外部指定別名時,需要將外部類的屬性放到別名後. var name : String = "scott" private var sal : Double = 1.2 }
外部類名.this 等價 外部類名別名,需要注意的是當給外部指定別名時,需要將外部類的屬性放到別名後。
二、型別投影
首先,展示一段程式碼中的一個錯誤:
class ScalaOuterClass { myOuter => class ScalaInnerClass { //成員內部類 def test(ic:ScalaInnerClass): Unit = { System.out.println("使用了型別投影:"+ic) } } object Scala01_class { def main(args: Array[String]): Unit = { val outer1 : ScalaOuterClass = new ScalaOuterClass(); val outer2 : ScalaOuterClass = new ScalaOuterClass(); val inner1 = new outer1.ScalaInnerClass() val inner2 = new outer2.ScalaInnerClass() inner1.test(inner1) inner1.test(inner2) // inner1.test(inner2) // error, 需要outer1.ScalanInner而inner2屬於outer2.ScalanInner } }
在此段程式碼中,inner1.test(inner2)會發生編譯錯誤,因為在Scala中,內部類例項和外部類的物件是關聯的,並不是像Java中那樣只看型別,此時inner1中的test方法的引數型別要求的是outer1.ScalaInnerClass。
Java中的內部類從屬於外部類,因此在java中inner.test(inner2) 就可以,因為是按型別來匹配的。
Scala中內部類從屬於外部類的物件,所以外部類的物件不一樣,創建出來的內部類也不一樣,無法互換使用
所以為了解決這種問題,那麼就引出了型別投影的技術,即在方法宣告上,如果使用 外部類#內部類 的方式,表示忽略內部類的物件關係,等同於Java中內部類的語法操作,我們將這種方式稱之為型別投影(即:忽略物件的建立方式,只考慮型別)
將上面的程式碼中的test方法的引數型別修改為"ic: ScalaOuterClass#ScalaInnerClass",即可解決這樣的錯誤。所以型別投影的作用就是遮蔽外部物件對內部類物件的影響。