java为什么对空引用调用方法会成功编译?
正在尝试执行这段代码
public class Main {
public static void main(String... args) {
new Main();
}
Main() {
A a = null;
a.foo();
}
}
class A {
void foo() {}
}
很明显,我将得到一个NullPointerException
,因为a已初始化为null
。代码编译是因为我(编码者)知道变量a
只能在此位置为null,而它(编译器)。。。事实上,它也知道这一点,以至于我得到了警告信息
Null pointer access: The variable a can only be null at this location
我的问题是,既然我和it都知道会抛出异常,为什么允许我的代码编译?有没有可能不出现例外情况
编辑:
换句话说,为什么我会在这样的事情中遇到编译器错误
try {
throw new Exception();
int x = 0;
} catch (Exception e) {
}
而不是在这方面
try {
if(true)throw new Exception();
int x = 0;
} catch (Exception e) {
}
放得很差:编译器如何区分阻塞与不阻塞“明显错误”
# 1 楼答案
从Java spec
4.12.2
还有, 例如,考虑:
这在我的NetBeans中给出了一个错误,即无法访问下面的行
再一次
现在你期待什么?同样的事?不是。它进入无限循环。 同样,您应该能够在代码中捕获NPE。这是允许的。因此,对于不同类型的歧义,可能存在许多组合。这很难选择&;限制
# 2 楼答案
null
不是compile time constant。编译器在编译时不知道A a = null;
的计算结果为null
进一步阅读:
Why isn't null a compile time constant
# 3 楼答案
我可能不完全正确,但应该归咎于解析器。我实现了一个
Java parser 1.5
,它基本上调用compilationUnit()
。首先获取源的流流被标记化(创建标记——关键字、变量……所有较小的部分)。然后,它可能会进行多次调用——例如,如果Java程序必须以关键字开头,那么它可能会查找访问说明符。之后,解析器需要有关键字“class”。它会在关键词之后找到其他可能性。我可以写
public class{}
或public int i;
。如果得到正确的关键字,解析将继续,否则将抛出一个ParseException
例如,我在解析器中做了一个小改动:
致:
恢复块看起来像:
我刚才做了什么?我恢复了解析器抛出的异常,即使没有方法或只有语句。例如
我现在没有错误。我做了些改变。因此,如果希望解析器在这种情况下报告异常,可以实现解析器:)希望您现在就得到它
# 4 楼答案
它可以编译,因为Java语言规范并不禁止它。谁知道呢,也许你想在调用者中捕捉这个
NullPointerException
。这不是最好的代码设计,但JLS允许这样做请注意,Eclipse编译器可以配置为此时显示错误。默认情况下,它会发出警告:
此外,静态代码分析器(如FindBugs)将触发此代码的警告
为什么不被JLS禁止的问题是基于观点的。但是请注意,现在无法添加此类功能,因为这可能会破坏向后兼容性。我相信,有一个现有的代码实际上可能依赖于这种行为