Psh*_*emo 76 java static initialization local-variables jls
尝试x通过未初始化的局部变量访问静态字段时,出现Foo foo; foo.x编译错误Variable 'foo' might not have been initialized。
class Foo{
public static int x = 1;
public static void main(String[] args) {
Foo foo;
System.out.println(foo.x); // Error: Variable 'foo' might not have been initialized
}
}
Run Code Online (Sandbox Code Playgroud)
它可能看起来像这样的错误是有道理的,但直到我们意识到,访问static成员编译器不实际使用值的变量,但只有它的类型。
例如,我可以foo使用value 进行初始化,null这将使我们能够x毫无问题地进行访问:
Foo foo = null;
System.out.println(foo.x); //compiles and while running prints 1!!!
Run Code Online (Sandbox Code Playgroud)
之所以如此,x是因为编译器意识到这是静态的,并foo.x像对待其编写时一样对待Foo.x(至少这是我到目前为止所认为的)。
那么,为什么编译器突然坚持要有foo一个在那个地方不会使用的值?
(免责声明:这不是在实际应用中使用的代码,只是一种有趣的现象,我在Stack Overflow上找不到答案,因此我决定对此进行询问。)
Nex*_*vis 72
如果该字段是静态的:
计算主表达式,并丢弃结果。如果主表达式的评估突然完成,则字段访问表达式由于相同的原因而突然完成。
较早的地方指出通过标识字段访问 Primary.Identifier。
这表明,即使它似乎不使用Primary,它仍然会被评估,然后丢弃结果,这就是为什么需要对其进行初始化的原因。如评估中所述,当报价中止访问时,这可能会有所不同。
编辑:
这是一个简短的示例,目的Primary是直观地证明即使丢弃了结果,也对进行了评估:
class Foo {
public static int x = 1;
public static Foo dummyFoo() throws InterruptedException {
Thread.sleep(5000);
return null;
}
public static void main(String[] args) throws InterruptedException {
System.out.println(dummyFoo().x);
System.out.println(Foo.x);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,您可以看到dummyFoo()仍会进行评估,因为print会延迟5秒钟,Thread.sleep()即使它始终返回一个null被丢弃的值。
如果表达式未评价的print会瞬间出现,其可以当类中可以看出Foo,直接用于访问x与 Foo.x。
注意: 方法调用也被视为§15.8主表达式中Primary所示。
rac*_*man 14
保持规则尽可能简单有其价值,“不要使用可能尚未初始化的变量”非常简单。
更重要的是,有一种建立静态方法的方法-始终使用类名,而不是变量。
System.out.println(Foo.x);
Run Code Online (Sandbox Code Playgroud)
变量“ foo”是不必要的开销,应删除,并且编译器错误和警告可以被视为有助于实现这一目标。