目录

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


一、前言:

  • 我们之前学习了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。