内部类

静态内部类

如何访问外部类的私有类变量?

通过编译阶段生成的一个访问外部类的 static 的 access$x00 方法,然后在静态内部类中,通过外部类的类名调用,如 OuterClass.access$x00

非静态内部类

编译时对内部类构造函数上会默认注入外部类引用,类似:

class Outer {
  class Inner {
    private final Outer this$0;
    Inner(Outer outer) { // 注意这里参数其实还有一个this参数在第一个
      this.this$0 = outer;
    }
  }
}

如何访问外部类的私有变量?

也是用 access 方法。

创建非静态内部类对象时,为什么会调用 getClass() 方法?

创建非静态内部类对象,通过编译查看字节码,会看到在初始化生成内部类对象前会调用 getClass() 方法,再去 new 内部类对象。

原因是,为了通过调用 outer.getClass()检查 outer 是否为 null,如果是则抛出 NPE。主要是想创建内部类前保证该 outer 是非空的

javac在编译创建内部类对象时生成的奇怪的getClass()调用是什么?

Why is getClass() called when we create an object for Inner class?

匿名内部类

与普通内部类相似。访问外部类私有变量也是用 access 方法。

如何访问外部变量?

void f() {
  int a = 123;
  new AnonymousClass() {
    {
      System.out.println(a);
    }
  };
}
class AnonymousClass {}

像如上 f() 里,匿名类对象是如何访问外部变量 a

其实就是编译时对匿名类构造方法里注入了外部变量,类似:

class AnonymousClass&1 {
  private final Outer this$0;
  private final int val$a;
  AnonymousClass&1(Outer outer, int a) {  // 注意这里参数其实还有一个this参数在第一个
    this.this$0 = outer;
    this.val$a = a;
  }
}

原来的 System.out.println(a); ,在编译期变成了 System.out.println(val$a);

为什么是 final ?

如上例子中描述,为什么编译时生成的匿名类 AnonymousClass&1val$a 是 final ,从而导致匿名类不能修改其值?

匿名类是通过保存外部变量值来访问该外部变量的,

匿名类中可能还有其他方法使用外部变量,如果不是 final 而允许修改的话,表面上会看起来怪,因为使用时变量已经被别的方法里改过了。也就是,原因只是避免开发人员弄混

其他语言像 Scala,是可以修改的。它在匿名类构造方法里注入时,其实传的是外部变量的一个封装类,匿名类保存的是该封装对象。这样,在外部和匿名类内部对外部变量的更新,其实是调用了该封装对象的更新方法,从而实现了同步。

注:其实普通内部类访问外部变量也一样,只不过很少用普通内部类来去访问(一般是使用匿名类)。

https://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class

为什么必须是final的呢?

posted @ 2019-09-04 11:44  eycuii  阅读(153)  评论(0编辑  收藏  举报