Java中的string和整数的空值
public class Test { public static void main(String[] args) { String s = null; String s1 = null; Integer i = null; Integer i1 = null; System.out.println(s+i); System.out.println(i+s); System.out.println(s+s1); try { System.out.println(i+i1); } catch (NullPointerException np) { System.out.print("NullPointerException"); } } }
问题很简单 – 为什么只在最后一行收到NullPointerException
?
你的代码使用两个不同的添加剂操作符 。 前三行使用string连接 ,而最后一行使用数字加法 。
string串联定义为将null
变为"null"
:
- 如果引用为
null
,则将其转换为string"null"
(四个ASCII字符n
,u
,l
,l
)。
因此没有NPE。
将两个Integer
对象一起添加需要将它们拆箱 。 这导致null
引用被解引用,导致NPE:
- 如果
r
为null,则取消装箱转换将引发NullPointerException
请注意,前三个+
运算符用法涉及string连接。 只有最后一个是实际的数字总和 。 当涉及string连接(涉及s
variables)时,Java编译器使用一些巧妙的技巧来提高性能。 它用StringBuilder
replace+
运算符。 例如,你的第一行被翻译成:
StringBuilder tmp = new StringBuilder(); tmp.append(s); tmp.append(i); System.out.println(tmp);
StringBuilder
是null
-friendly,所以无论你作为parameter passing什么,它都很好地用"null"
stringreplace它。
最后一行的情况是不同的。 在那里你引用了两个Integer
对象。 唯一的JVM可以在这里做的是取消他们( i.intValue()
),并做实际的计算。 对null
拆箱会导致NullPointerException
。
任何带有String
的串联( +
运算符)都会产生一个String
。 每个操作数首先转换为一个string(使用toString()
或使用值"null"
),然后连接。
但是最后的操作只涉及Integer
,所以以前的规则不适用。 而不是连接,它做了一个补充。 但是要添加两个Integer
,它会将对象( Integer
)转换为原始值(整数),如果Integer
为空,这是不可能的。 这就是为什么你得到一个NullPointerException
。
似乎是一个自动拆箱的情况。 如果你有两个Integer
第first
和second
,那么它们的加法结果是first.intValue() + second.intValue()
。 由于它们都是空的,导致NPE。
看看你的程序字节码。 您会注意到您的空对象正在作为parameter passing给PrintStream.print()方法。 print()方法的源代码使用String.valueOf(),如下所示:
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
应该指出,这个问题的答案应该从输出中显而易见:
C:\Temp>java Test nullnull nullnull nullnull NullPointerException