请看下面的代码。
class Foo{
public static int x = 1;
}
class Bar{
public static void main(String[] args) {
Foo foo;
System.out.println(foo.x); // Error: Variable 'foo' might not have been initialized
}
}
当你试图访问静态字段时,你会发现 x
经由 未初始化 局部变量 Foo foo;
编码 foo.x
产生编译错误。Variable 'foo' might not have been initialized
.
它可能是 似乎 这样的错误是有意义的,但只有在我们意识到要访问一个 static
成员,JVM实际上并不 使用 的 价值 的,而只是它的 类型.
例如,我可以初始化 foo
有价值 null
这样我们就可以访问 x
没有任何问题。
Foo foo = null;
System.out.println(foo.x); //compiles and at runtime prints 1!!!
这种情况下,编译器的工作原理是: x
是静态的,并将 foo.x
如是 Foo.x
至少我到现在为止是这么认为的)。
那么为什么编译器突然坚持要用 foo
有价值 它不会使用 完全没有?
免责声明:这不是在实际应用中会用到的代码,而是我在Stack Overflow上找不到答案的有趣现象,所以我决定问一下。
如果该领域是: 静态:
对初级表达式进行评估,结果被丢弃。. 如果Primary表达式的评估突然完成,字段访问表达式也会因为同样的原因突然完成。
前面说到字段访问是由 Primary.Identifier
.
这说明,即使它似乎没有使用的是 Primary
它仍然被评估,然后结果被丢弃,这就是为什么它需要被初始化。 当评估停止访问时,如引文中所说,这可能会有所区别。
EDIT:
这里有一个简短的例子,只是为了直观地演示一下。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);
}
}
这里你可以看到 dummyFoo()
仍在评估,因为 print
延迟了5秒 Thread.sleep()
尽管它总是返回一个 null
值,该值被丢弃。
如果表达式没有被评估,那么 print
会立即出现,这一点可以看出,当类 Foo
直接用于访问 x
与 Foo.x
.
注意: 方法调用也被认为是一种 Primary
如图 §15.8 主要表达方式.
第十六章. 肯定性分配
每个局部变量(§14.4)和每个空白的最终字段(§4.12.4, §8.3.1.2) 当对其值进行访问时,必须有一个确定的赋值。
其实这并不重要 什么 你试图通过一个局部变量来访问。规则是,在这之前,它应该被肯定地分配。
要评估 字段访问表达式 foo.x
జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ primary
其中的一部分(foo
)必须先进行评估。这意味着访问 foo
会发生,这将导致编译时错误。
对于每一个局部变量或空白最终字段x的访问,x必须在访问前被明确赋值。或发生编译时错误。
尽可能简单的规则是有价值的,"不要使用一个可能还没有初始化的变量 "就是最简单的。
更重要的是,调用静态方法有一个既定的方法--总是使用类名,而不是变量。
System.out.println(Foo.x);
变量 "foo "是不必要的开销,应该被移除,而编译器的错误和警告可以看作是帮助导致了这一点。
其他答案完美地解释了背后发生的机制。也许你还想知道Java规范背后的原理。我不是Java专家,不能给你原原本本的理由,但让我指出这一点。
Foo.x
是自然的)。)foo.x
(通过实例变量访问)?Foo.x
已经是 "简单访问 "的意思 x
",按理说 表情 foo.x
有着不同的意义;也就是说。言之有物 和访问 x
.希望有识之士能告诉我们真正的原因吧:-)