为什么匿名类不能访问其封闭类的变量?
问题内容:
我正在阅读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 spec
2.14中
引用)已消失:http
:
//java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html
不过,可以在Wayback机器上获得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;
}
请注意,尽管规范示例使用命名类,但相同的推理也适用于匿名类:
// ...
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
}