如果第二个示例有权访问外部变量,那么第二个示例会违反什么语义?
class A {
void f() {
int outer = 1;
// Access non-final outer variable through helper method
new A() {
int inner;
void init(int inner) {
this.inner = inner;
}
}.init(outer); // OK
// Access non-final outer variable through instance initializer
new A() {
{
// int inner = outer; // Does not compile
}
};
outer = 2;
}
}
答案 0 :(得分:1)
它与实例初始化器无关,而是与捕获外部局部变量这一事实有关。如果您在辅助方法中捕获外部局部变量,它同样不起作用:
new A() {
int inner;
void init() {
this.inner = outer;
}
}.init();
当捕获本地或匿名类中的外部局部变量时,该外部局部变量必须为final
(在Java 7中或之前)或有效{{1 } (在Java 8+中)。您的变量final
不是outer
,并且(在您最近的编辑之后)不是有效final
(这意味着如果它被声明为final
),因为您稍后会分配给它。
由于Java实现捕获的方式,捕获的局部变量必须是final
或有效final
。在Java中,当创建本地或匿名类的对象时,它捕获的任何局部变量都被分配(就像通过final
)到对象内部的单独的独立副本中(因为该对象可能比本地范围更长)它被创造了)。变量状态不是原始本地作用域和捕获它的对象之间的“共享”,即使它们具有相同的名称并且只声明了一个变量。因此,如果您可以分配给变量,则对变量的一个副本的更改不会反映在其他副本中,并且它将不一致。为防止出现这种情况,它们会阻止您分配给变量的任何版本,方法是要求它有效=
。