为什么实例初始值设定项要求Java中的外部变量使用* final *?

时间:2015-05-09 23:03:41

标签: java parameters anonymous-class

如果第二个示例有权访问外部变量,那么第二个示例会违反什么语义?

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;
    }
}

1 个答案:

答案 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)到对象内部的单独的独立副本中(因为该对象可能比本地范围更长)它被创造了)。变量状态不是原始本地作用域和捕获它的对象之间的“共享”,即使它们具有相同的名称并且只声明了一个变量。因此,如果您可以分配给变量,则对变量的一个副本的更改不会反映在其他副本中,并且它将不一致。为防止出现这种情况,它们会阻止您分配给变量的任何版本,方法是要求它有效=