1. 程式人生 > 實用技巧 >Scala中的巢狀類

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 = new
outer1.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
  class
ScalaInnerClass { //成員內部類 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",即可解決這樣的錯誤。所以型別投影的作用就是遮蔽外部物件對內部類物件的影響。