如果第二个示例可以访问外部变量,则会违反哪些语义?
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;
}
}
它与实例initializers 无关,而是与您捕获 的事实。如果您捕获助手方法中的外部局部变量,则同样行不通:
new A() {
int inner;
void init() {
this.inner = outer;
}
}.init();
当您 capture 局部或匿名类中的外部局部变量时,外部局部变量必须为 final
(在Java 7或之前)或有效地final
(在Java 8 )。您的变量outer
不是final
,并且(在最近的编辑之后)不是有效的final
(这意味着如果将其称为final
),因为您以后分配给它。
由于Java实施捕获的方式,捕获的本地变量必须为final
或有效的final
。在Java中,当创建本地或匿名类的对象时,将其捕获的任何局部变量分配(就像由=
)分配到对象内部的单独独立副本中(因为对象可能比创建其创建的本地范围更高)。最初的本地范围和捕获它的对象之间并未"共享"变量状态,即使它们具有相同的名称,并且只声明了一个变量。因此,如果您可以将变量分配给变量的一个副本,则不会反映在其他副本中,这将是不一致的。为了防止这种情况,它们通过要求有效的final
来防止您分配到变量的任何版本。