为什么引用匿名内部类的名称在它是成员时起作用,而不是变量?

时间:2015-05-08 17:44:35

标签: java

对不起标题血,我不知道如何在一行中描述问题。如果你有建议,我会打开。

假设您有以下课程:

public class SomeClass {
    // doesn't even need to be final, which is freaky
    Runnable memberRunnable = new Runnable() {
        public void run() {
            SomeOtherClass.someMethod(memberRunnable); // this works
        }
    }
    public void someMethod() {
        final Runnable varRunnable = new Runnable() {
            public void run() {
                SomeOtherClass.someMethod(varRunnable); // compiler error - "varRunnable" might not have been initialized
            }
        }
    }
}

为什么memberRunnable能够从run()内部访问自己,而varRunnable却不能? AFAICS它是完全相同的结构。

我知道,显然你可以使用this。我只是想知道为什么编译器会在两种情况之间产生差异,这两种情况看起来完全相同。也是为什么它认为varRunnable可能没有被初始化,当它显然是在那时。

有人可能会说,如果Runnable是一个类(它是一个接口),它的构造函数可能会尝试调用run(),从而实际上遇到了一个未初始化引用的场景。但是,memberRunnable也应如此,但这种情况有效。

有趣的是,如果您使用类Runnable而不是rowControllerAtIndex,则没有任何变化,在这种情况下,上述场景(构造函数调用重写方法)实际上可能发生。这意味着,在这种情况下,您可以在运行时遇到“未初始化的字段”(虽然没有尝试过),这是相当愚蠢的,因为编译器应该防范它。

1 个答案:

答案 0 :(得分:9)

  

另外,为什么它认为varRunnable可能没有被初始化,当它显然是在那时。

不,该变量不是(在一般情况下)保证在该点初始化。

假设,仅仅为了论证,Runnable是一个抽象类(而不是一个接口),而Runnable的构造函数称为this.run()。由于Runnable的构建发生在分配之前,这将导致在分配发生之前访问varRunnable

换句话说,它将导致访问未初始化的局部变量。请注意,这比访问尚未显式初始化的字段更糟糕,因为局部变量未初始化为默认值。事实上更糟糕的是,禁止访问未初始化的局部变量,而正如您刚刚发现的那样,允许访问尚未显式初始化的字段。 (最终字段不会改变这一点。最终字段也有默认值,它们实际上可以在构造函数中更改(一次)。)

来源:我是一名javac开发人员。