方法本地内部类访问方法的局部变量

嗨,我正在浏览关于内部类的SCJP书,发现这个陈述,它就是这样的。

方法本地类只能引用标记为final的局部变量

在解释中,指定的原因是关于本地类对象的范围和生命周期以及堆上的局部变量,但我无法理解。 我在这里错过任何关于final事情吗

原因是,当创建方法本地类实例时,它引用的所有方法局部变量实际上都是由编译器复制到其中的。 这就是为什么只能访问final变量的原因。 final变量或引用是不可变的,因此它与方法本地对象中的副本保持同步。 如果不是这样,原始值/引用可以在创建方法本地类之后更改,让位于令人困惑的行为和细微的错误。

从JavaSpecialist简报no中考虑这个例子。 25 :

 public class Access1 { public void f() { final int i = 3; Runnable runnable = new Runnable() { public void run() { System.out.println(i); } }; } } 

编译器将内部类转换为:

 class Access1$1 implements Runnable { Access1$1(Access1 access1) { this$0 = access1; } public void run() { System.out.println(3); } private final Access1 this$0; } 

由于i的值是final,因此编译器可以将其“内联”到内部类中。

在我看来,从方法本地类(例如匿名类)访问局部变量是一件危险的事情。 它是由编译器允许的,但它需要很好地理解正在发生的事情。

当内部类被实例化时,它所使用的对局部变量的所有引用都被复制,并作为隐式构造函数参数传递(检查字节码)。 实际上编译器可以允许使引用非最终,但它会令人困惑,因为如果方法在实例化之后改变引用,会发生什么并不清楚。

但是,参考最终并不能消除所有问题。 虽然引用是不可变的,但引用后面的对象可能仍然是可变的。 内部类的实例化直到其激活之间完成的对象的任何突变都将被内部类看到,并且有时这不是程序员的意图。