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",即可解决这样的错误。所以类型投影的作用就是屏蔽外部对象对内部类对象的影响。

 

posted @ 2020-09-16 21:06  有心有梦  阅读(762)  评论(0编辑  收藏  举报