为什么匿名类不能访问其封闭类的变量?
我正在阅读java中的匿名类,它说你可以访问封闭类的方法,但不能访问局部变量。 为什么会这样? 我在说这个:
编辑:旧的例子是错误的不反映我的意思。 这应该是一个更好的例子,根据它在“访问封闭类的成员”部分http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html中所写的内容。
public class MyClass { public interface SomeInterface{ public void someOtherMethod(); } public void someMethod(int someLocalVar) { SomeInterface myClass = new SomeInterface(){ public void someOtherMethod(){ someLocalVar = 0; // This must be final to work } } } }
那么这个限制解决有什么问题呢?
这来自早期版本的Java内部类规范。
官方规范URL,例如来自VM规范2.14 ,因链接腐烂而消失: http : //java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html
1999年1月17日快照可以在回程机器上获得,相应的规格部分是对局部变量的引用 。
事物应该如何工作的方式描述如下(我标记了最相关的声明粗体):
块的本地类定义可以访问局部变量。 这使编译器的工作变得复杂。 这是本地类的前一个示例:
Enumeration myEnumerate(final Object array[]) { class E implements Enumeration { int count = 0; public boolean hasMoreElements() { return count < array.length; } public Object nextElement() { { return array[count++]; } } return new E(); }
为了使局部变量对内部类的方法可见,编译器必须将变量的值复制到内部类可以访问它的位置。 对同一变量的引用可以在不同的地方使用不同的代码序列,只要在任何地方产生相同的值,使得名称始终在其范围的所有部分中引用相同的变量。
按照惯例,像
array
这样的局部变量被复制到内部类的私有字段val$array
中。 (因为array
是final
,所以这些副本永远不会包含不一致的值。) ...
你知道,语言设计者希望每次创建这样的副本时,复制的局部变量的值都是“一致的”。 他们的动机很可能是开发人员不必担心在内部类的副本之外查看它是否已被更改:
Enumeration myEnumerate(Object array[], int copy) { // array not final, let's see... for (int i = 0, i < 2; i++ ) { // loop to have several copies class E implements Enumeration { int count = 0; public boolean hasMoreElements() { return count < array.length; } public Object nextElement() { { return array[count++]; } } // we hope to be done with E... oh no array = null; // not final => can change if (i == copy) { return new E(); // we need to look outside of E // to figure value of array it uses } } return null; }
注意虽然spec示例使用命名类,但同样的推理适用于匿名类:
// ... for (int i = 0, i < 2; i++ ) { // loop to have several copies if (i == copy) { return new Enumeration() { int count = 0; public boolean hasMoreElements() { return count < array.length; } public Object nextElement() { { return array[count++]; } } // we hope to be done... oh no } array = null; // not final => can change }
内部类可以访问封闭类的final
变量。
这是一个有趣的备忘录:
实际上,原型实现确实允许从内部类中引用非最终变量。 用户强烈抗议,抱怨他们不想要这个! 原因很有意思:为了支持这些变量,有必要对它们进行堆分配,并且(至少在那个时候),普通的Java程序员对堆分配和垃圾收集仍然相当不安。 当没有出现“new”关键字时,他们不赞成在“桌面下”执行堆分配的语言。
匿名类对象的生命周期可以比创建它的方法持续更长时间,但它的持续时间不能超过父对象的生命周期。
考虑以下
public void runSomething() { int a = 5; new Thread(new Runnable() { public void run() { a = 10; } } }
哪个’a’变量是Runnable要修改的。 无法更改方法的本地,因为该方法不再在堆栈上。
正如Rafael Osipov在评论中所说,你绝对可以从匿名类访问mSomeVar
,一个封闭类的实例变量。 所以你的问题没有意义。