public static void main(String[] args) {
String s1 = null;
String s2;
s1.trim(); //No compile error. But run time error
s2.trim(); //compile error.
}
s1
在上面的代码中,初始化编译器知道s1
is后没有赋值null
。那为什么不显示s1.trim()
类似的编译错误s2
?
public static void main(String[] args) {
String s1 = null;
String s2;
s1.trim(); //No compile error. But run time error
s2.trim(); //compile error.
}
s1
在上面的代码中,初始化编译器知道s1
is后没有赋值null
。那为什么不显示s1.trim()
类似的编译错误s2
?
因为s2
没有被初始化并且s1
被初始化为null
对于问题 1:您实际上是在执行trim()
操作null
,因此它将NullPointerException
按应有的方式抛出 NPE ( )。
对于问题 2: 请参阅JLS 的§4.12.5以获得非常详细的解释:
在使用局部变量之前,必须通过初始化或赋值来显式地赋予一个值,编译器可以使用明确赋值的规则对其进行验证。
String s2;
这是一个局部变量。局部变量没有给出默认值,您必须在使用前提供一个默认值,否则编译器会报错。您无法编译代码的原因。
String s1 = null;
您正在初始化此局部变量。所以没有编译问题,但你不能对空的东西执行修剪操作。所以你得到 NPE 这是一个运行时异常,默认情况下不能被缓存(尽管你可以)。
由于 s1 已初始化,编译器很高兴,尽管它可能会发出有关可能的 NullPointerException 的警告
1)空指针异常..因为没有对象但对空进行操作;2)没有初始化就不能使用局部变量
局部变量必须显式初始化才能使用。设置s1=null
是一种初始化,尽管相对无用。由于s2
在堆栈上且未初始化,因此无法使用。
s1
得到一个运行时异常,但s2
得到一个编译时错误。
在创建字符串对象时,我们应该初始化一些值。
String s1 = null;
它持有空值。
String s2;
但变量 s2 为空值但未赋值。
这是因为 java 编译器在编译代码时会查找赋值运算符 (=)。当编译器在 s1 的情况下触发“=”符号时,它认为 s1 已初始化,而与初始化值无关。而在 s2 的情况下,编译器找不到赋值运算符,因此在词法阶段它会在错误表中创建一个条目,说明“变量 s2 可能尚未初始化”
Java 编译器会检查局部变量是否被初始化。如果不是,编译器会抛出错误。这是必需的,因为与实例变量不同,java 不会使用其默认值初始化局部变量。一旦变量被初始化,即使它是用 null 初始化的,编译器也不会抱怨,因为编译器假设,在程序执行过程中,变量会在某个地方用非 null 值重新初始化。编译器,无法检查在程序过程中重新初始化的值,因为该值在运行时可以是任何值。但是如果该值仍然为 null,将调用实例方法,JVM 会抛出 NullPointerException,因为它仅在运行时才知道。说得通?
让我们以 JLS 中的明确分配为例:
{
int k;
int n = 5;
if (n > 2)
k = 3;
System.out.println(k); /* k is not "definitely assigned"
before this statement */
}
有人可能会说编译器知道执行肯定会到达if
块内部,导致赋值,k
所以它应该编译得很好,但事实并非如此。
我认为这是 Java 作者做出的决定,他们希望编译器有多聪明,同时牢记编译时间和/或其他因素的可接受值。