为什么匿名内部类在使用时,方法参数和方法内局部变量必须加final?

 参考解答

class A {
  public static void main(String[] args){
    int a = 10;
    final int b = a;
    Runnable r = new Runnable(){
      public void run(){
        System.out.println(b);
      }
    };
  }
}

如上例所示,javac会在编译时生成 A.class 和 A$1.class,它俩是一个平级的关系。 而A$1.class 想直接访问A.class中方法内的局部变量理论上是不行的,因此javac做了一点手脚,它编译生成A$1.class时,会将x作为A$1.class的成员变量,这个成员变量对我们程序员而言是“不可见的”,并且它的取值在一开始就被固定了。

上述代码的伪代码是:

class A$1 implements Runnable{
  int val;
  public A$1(int val){
    this.val = val
  } 
  public void run() {
    System.out.println(this.val);
  }
}

class A {
  public static void main(String[] args){
    int a = 10;
    final int b = a;
    Runnable r = new A$1(b);
    System.out.println(b); // 打印10
    r.run(); // 打印10
  }
}

现在假设b是不final的,编译也可以通过,那么伪代码变成:

class A$1 implements Runnable{
  int val;
  public A$1(int val){
    this.val = val
  } 
  public void run() {
    System.out.println(this.val);
  }
}

class A {
  public static void main(String[] args){
    int a = 10;
    int b = a;
    Runnable r = new A$1(b); 
    // 如果在这里修改b的值
    b = 20;
    System.out.println(b); // b的值已经改为20
    r.run(); // 打印的是A$1对象内部的成员变量,结果还是刚开始的10,造成不一致
  }
}

如果方法内局部变量和内部类的成员变量能够相互感知改变,这个特性实现了的话,称之为闭包(closure),而java偷懒没有实现,java是在语法上规定引用的局部变量必须是final的,避免上述的不一致情况发生。


results matching ""

    No results matching ""