关于java:为什么我的局部变量最终可以从匿名类访问?

Why should my local variables be final to be accessible from anonymous class?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Cannot refer to a non-final variable inside an inner class defined in a different method

将局部变量声明为最终变量以便从匿名类访问这些变量的规则背后的原因是什么?


...when an object of the
anonymous class is instantiated,
copies of the final local variables
and method parameters referred to by
the object's methods are stored as
instance variables in the object. The
methods in the object of the anonymous
class really access those hidden
instance variables.

Thus, the local
variables and method parameters
accessed by the methods of the local
class must be declared final to
prevent their values from changing
after the object is instantiated.

从这里开始。


当您从匿名类访问final变量时,编译器会秘密地将其值复制到匿名类的成员变量中。如:

1
2
3
4
5
6
7
8
Runnable foo() {
  final int x = 42;
  return new Runnable() {
    void run() {
      System.out.writeln(x);
    }
  };
}

变成:

1
2
3
4
5
6
7
8
9
10
11
12
13
// the actual name is generally illegal in normal java syntax
class internal_Runnable implements Runnable {
  final int x;
  internal_Runnable(int _x) { x = _x; }
  void run() {
    System.out.writeln(x);
  }
}

void foo() {
  final x = 42;
  return new internal_Runnable(x);
}

如果变量不是最终变量,并且允许更改,则匿名类实例中缓存的值可能不同步。这可以通过使用闭包来避免,也就是说,一个包含所有局部变量值的对象,原始函数和新的匿名类实例都可以访问该对象。例如,.NET使用闭包。然而,这可能招致性能冲击,也许正是出于这个原因,Java语言设计者决定不支持完全闭包。


匿名类是单独的类。它无法访问方法中的控制流。如果要重新分配匿名类中的变量,实际上只会重新分配匿名类的变量副本。这将是非常容易出错的,因此设计选择使其成为一个错误。

如果你想解决这个问题,可以使用AtomicReference


这是因为匿名内部对象可能会将其上下文持久化,如果它引用的是非final变量,那么它将与不再存在的事物进行对话。