7.12 嵌套类(Nested Class)

7.12.1 嵌套类:类中的类

类可以嵌套在其他类中,可以嵌套多层:

  1. class NestedClassesDemo {
  2. class Outer {
  3. private val zero: Int = 0
  4. val one: Int = 1
  5. class Nested {
  6. fun getTwo() = 2
  7. class Nested1 {
  8. val three = 3
  9. fun getFour() = 4
  10. }
  11. }
  12. }
  13. }

测试代码:

  1. val one = NestedClassesDemo.Outer().one
  2. val two = NestedClassesDemo.Outer.Nested().getTwo()
  3. val three = NestedClassesDemo.Outer.Nested.Nested1().three
  4. val four = NestedClassesDemo.Outer.Nested.Nested1().getFour()
  5. println(one)
  6. println(two)
  7. println(three)
  8. println(four)

我们可以看出,访问嵌套类的方式是直接使用 类名., 有多少层嵌套,就用多少层类名来访问。

普通的嵌套类,没有持有外部类的引用,所以是无法访问外部类的变量的:

  1. class NestedClassesDemo {
  2. class Outer {
  3. private val zero: Int = 0
  4. val one: Int = 1
  5. class Nested {
  6. fun getTwo() = 2
  7. fun accessOuter() = {
  8. println(zero) // error, cannot access outer class
  9. println(one) // error, cannot access outer class
  10. }
  11. }
  12. }
  13. }

我们在Nested类中,访问不到Outer类中的变量zero,one。 如果想要访问到,我们只需要在Nested类前面加上inner关键字修饰,表明这是一个嵌套的内部类。

7.12.2 内部类(Inner Class)

类可以标记为 inner 以便能够访问外部类的成员。内部类会带有一个对外部类的对象的引用:

  1. class NestedClassesDemo {
  2. class Outer {
  3. private val zero: Int = 0
  4. val one: Int = 1
  5. inner class Inner {
  6. fun accessOuter() = {
  7. println(zero) // works
  8. println(one) // works
  9. }
  10. }
  11. }

测试代码:

  1. val innerClass = NestedClassesDemo.Outer().Inner().accessOuter()

我们可以看到,当访问inner class Inner的时候,我们使用的是Outer().Inner(), 这是持有了Outer的对象引用。跟普通嵌套类直接使用类名访问的方式区分。

7.12.3 匿名内部类(Annonymous Inner Class)

匿名内部类,就是没有名字的内部类。既然是内部类,那么它自然也是可以访问外部类的变量的。

我们使用对象表达式创建一个匿名内部类实例:

  1. class NestedClassesDemo {
  2. class AnonymousInnerClassDemo {
  3. var isRunning = false
  4. fun doRun() {
  5. Thread(object : Runnable {
  6. override fun run() {
  7. isRunning = true
  8. println("doRun : i am running, isRunning = $isRunning")
  9. }
  10. }).start()
  11. }
  12. }
  13. }

如果对象是函数式 Java 接口,即具有单个抽象方法的 Java 接口的实例,例如上面的例子中的Runnable接口:

  1. @FunctionalInterface
  2. public interface Runnable {
  3. public abstract void run();
  4. }

我们可以使用lambda表达式创建它,下面的几种写法都是可以的:

  1. fun doStop() {
  2. var isRunning = true
  3. Thread({
  4. isRunning = false
  5. println("doStop: i am not running, isRunning = $isRunning")
  6. }).start()
  7. }
  8. fun doWait() {
  9. var isRunning = true
  10. val wait = Runnable {
  11. isRunning = false
  12. println("doWait: i am waiting, isRunning = $isRunning")
  13. }
  14. Thread(wait).start()
  15. }
  16. fun doNotify() {
  17. var isRunning = true
  18. val wait = {
  19. isRunning = false
  20. println("doNotify: i notify, isRunning = $isRunning")
  21. }
  22. Thread(wait).start()
  23. }

测试代码:

  1. NestedClassesDemo.Outer.AnonymousInnerClassDemo().doRun()
  2. NestedClassesDemo.Outer.AnonymousInnerClassDemo().doStop()
  3. NestedClassesDemo.Outer.AnonymousInnerClassDemo().doWait()
  4. NestedClassesDemo.Outer.AnonymousInnerClassDemo().doNotify()

输出:

  1. doRun : i am running, isRunning = true
  2. doStop: i am not running, isRunning = false
  3. doWait: i am waiting, isRunning = false
  4. doNotify: i notify, isRunning = false

关于lambda表达式以及函数式编程,我们将在下一章中学习。