对不起标题血,我不知道如何在一行中描述问题。如果你有建议,我会打开。
假设您有以下课程:
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
,则没有任何变化,在这种情况下,上述场景(构造函数调用重写方法)实际上可能发生。这意味着,在这种情况下,您可以在运行时遇到“未初始化的字段”(虽然没有尝试过),这是相当愚蠢的,因为编译器应该防范它。
答案 0 :(得分:9)
另外,为什么它认为
varRunnable
可能没有被初始化,当它显然是在那时。
不,该变量不是(在一般情况下)保证在该点初始化。
假设,仅仅为了论证,Runnable
是一个抽象类(而不是一个接口),而Runnable
的构造函数称为this.run()
。由于Runnable
的构建发生在分配之前,这将导致在分配发生之前访问varRunnable
。
换句话说,它将导致访问未初始化的局部变量。请注意,这比访问尚未显式初始化的字段更糟糕,因为局部变量未初始化为默认值。事实上更糟糕的是,禁止访问未初始化的局部变量,而正如您刚刚发现的那样,允许访问尚未显式初始化的字段。 (最终字段不会改变这一点。最终字段也有默认值,它们实际上可以在构造函数中更改(一次)。)
来源:我是一名javac开发人员。