Kotlin系列(十九):嵌套类、内部类与this的特殊用法

  发布日期:   2017-10-27
  最新修改:   2020-10-17
  阅读次数:   235 次

一、前言:

  • 我们之前学习了Kotlin类相关的知识,包括类的定义、类成员的定义、类的继承、成员的重写等,我们还学习了可见性修饰符。

  • 本章我们将继续学习类方面的知识:嵌套类、内部类和特殊场景下this的使用。


二、嵌套类

  • 类可以嵌套在其他类中:

      class Outer {
              private val bar: Int = 1
              class Nested {
                      fun foo() = 2
              }
      }
    
      val demo = Outer.Nested().foo() // == 2

三、内部类

  • 内部类用 inner标记,通过inner标记的内部类能够访问外部类的成员。

  • 内部类会带有一个对外部类的对象的引用:

      class Outer {
              private val bar: Int = 1
              inner class Inner {
                      fun foo() = bar
              }
      }
    
      val demo = Outer().Inner().foo() // == 1

四、匿名内部类

  • 在Java中我们经常会用到接口这个东西

  • 我们来下Java中如何实现:

  • 首先、线定义一个接口类:

      /**
       * Created by 安杰 on 2017/10/27. */
       public class UserLisenter {
              interface onClickListener {
                      void onClick1(int i);
    
                      void onClick2(int j);
              }
    
              public void addLisenter(onClickListener lisenter) {
    
              }
      }
  • 然后我们是实现这么一个接口类:

      import org.junit.Test;
    
      /**
       * Created by 安杰 on 2017/10/27. */
    
       public class TestJava {
              @Test
          public void test() {
                      UserLisenter userLisenter = new UserLisenter();
                      userLisenter.addLisenter(new UserLisenter.onClickListener() {
                              @Override
          public void onClick1(int i) {
    
                              }
    
                              @Override
          public void onClick2(int j) {
    
                              }
                      });
              }
      }
  • Ok,我们再看一下Kotlin的版本,再Kotlin中我们可以通过创建匿名内部类来实现,也就是没有名字的类;

      @Test
      fun test2() {
              val u = UserLisenter();
              u.addLisenter(object : UserLisenter.onClickListener {
                      override fun onClick1(i: Int) {
                      }
    
                      override fun onClick2(j: Int) {
                      }
    
              })
      }
  • 当然,如果我们的接口里面只有一个回调函数,我们还可以直接用lambda表达式。

  • 代码修改如下:

      /**
       * Created by 安杰 on 2017/10/27. */
       public class UserLisenter {
    
              interface onClickListener {
                      void onClick1(int i);
    
              }
    
              public void addLisenter(onClickListener lisenter) {
    
              }
      }
  • 实现代码如下:

      @Test
      fun test2() {
              val u = UserLisenter();
              u.addLisenter { i ->
          //实现代码
          }
      }

五、This 表达式

  • 一旦用到内部类、嵌套类或者lambda表达式,我们需要使用外面的数据时,就需要特殊处理我们的this了。
  • 为了表示当前的 接收者 我们使用 this 表达式:
  • 在类的成员中,this 指的是该类的当前对象。
  • 在扩展函数或者带接收者的函数字面值中,
  • this*表示在点左侧传递的 接收者 参数。
  • 如果 this没有限定符,它指的是最内层的包含它的作用域。要引用其他作用域中的 this,请使用 _标签限定符_:

限定的 this

  • 要访问来自外部作用域的this*,我们使用this@label,其中 @label 是一个代指 *this 来源的标签:

      @Test
      fun test2() {
          var name = "test2"
          class A { // 隐式标签 @A
          var name = "A";
              inner class B { // 隐式标签 @B
                var name = "B";
    
                  fun say() {
                      val a = this@A.name // 类A 的 this
                      println("this@A $a")
                      val b = this@B.name // 类B 的 this
                      println("this@B $b")
    
                      val c = this.name 
                      println("this $c")
    
                      val funLit2 = { s: String ->
                      val d1 = this.name;
                      println("funLit2 this $d1")
    
                    }
    
                funLit2("funLit2 name");
    
                  }
              }
          }
    
          val a = A().B();
          a.say();
    
      }
  • 运行结果为:

      this@A A
      this@B B
      this  B
      funLit2 this B
  • 结果分析:

  • 可以看到,通过@类名可直接获取外部类的this引用。

  • 在lambda表达式中this指向外面第一层的类B。


   转载规则

《Kotlin系列(十九):嵌套类、内部类与this的特殊用法字》GajAngels 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。