考虑使用Java编写的以下代码片段。它不会编译。
package temppkg;
final public class Main
{
private String x;
private int y;
private void show()
{
String z;
int a;
System.out.println(x.toString()); // Causes a NullPointerException but doesn't issue a compiler error.
System.out.println(y); // Works fine displaying its default value which is zero.
System.out.println(z.toString()); // Causes a compile-time error - variable z might not have been initialized.
System.out.println(a); // Causes a compile-time error - variable a might not have been initialized.
}
public static void main(String []args)
{
new Main().show();
}
}
为什么在上面的代码片段中声明的类成员(x和y)不会发出任何编译时错误,即使它们没有显式初始化并且只需要初始化局部变量?
发布于 2011-12-15 23:08:26
如果有疑问,请检查Java Language Specification (JLS)。
在the introduction中,您可以找到:
第16章描述了该语言确保在使用前明确设置局部变量的精确方法。虽然所有其他变量都会自动初始化为默认值,但Java编程语言不会自动初始化局部变量,以避免屏蔽编程错误。
chapter 16的第一段说,
Java编译器必须执行特定的保守流程分析,以确保对于每个局部变量或空白
字段f的每次访问,f都在访问之前被明确赋值;否则将会发生编译时错误。
默认值本身在section 4.12.5中。该部分打开时会显示以下内容:
每个类变量、实例变量或数组组件在创建时都使用默认值进行初始化。
然后,...and继续列出所有默认值。
JLS其实并不难理解,我发现自己越来越多地使用它来理解为什么Java要做does...after所有的事情,这就是Java圣经!
发布于 2011-12-15 22:53:20
为什么他们会发出编译警告呢?因为实例变量String将获得默认值null,而int将获得默认值0。
编译器无法知道x.toString()会导致运行时异常,因为null的值实际上是在运行后才设置的。
发布于 2011-12-15 23:04:04
通常,编译器不能确定某个类成员以前是否已初始化。例如,可以有一个setter方法设置类成员的值,另一个方法访问该成员。编译器在访问该变量时不能发出警告,因为它不知道setter之前是否被调用过。
我同意在这种情况下(成员是私有的,并且没有单一的方法来写入变量),它似乎会引发编译器的警告。实际上,你仍然不能确定这个变量还没有被初始化,因为它可能已经通过reflexion被访问过了。
使用局部变量更容易,因为它们不能从方法外部访问,甚至不能通过reflexion (afaik,如果错误请纠正我),所以编译器可以更有帮助,并警告我们未初始化的变量。
我希望这个答案能帮助你:)
https://stackoverflow.com/questions/8521917
复制相似问题