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字符null )。

因此没有NPE。

将两个Integer对象一起添加需要将它们拆箱 。 这导致null引用被解引用,导致NPE:

  • 如果r为null,则取消装箱转换将引发NullPointerException

请注意,前三个+运算符用法涉及string连接。 只有最后一个是实际的数字总和 。 当涉及string连接(涉及svariables)时,Java编译器使用一些巧妙的技巧来提高性能。 它用StringBuilderreplace+运算符。 例如,你的第一行被翻译成:

 StringBuilder tmp = new StringBuilder(); tmp.append(s); tmp.append(i); System.out.println(tmp); 

StringBuildernull -friendly,所以无论你作为parameter passing什么,它都很好地用"null"stringreplace它。

最后一行的情况是不同的。 在那里你引用了两个Integer对象。 唯一的JVM可以在这里做的是取消他们( i.intValue() ),并做实际的计算。 对null拆箱会导致NullPointerException

任何带有String的串联( +运算符)都会产生一个String 。 每个操作数首先转换为一个string(使用toString()或使用值"null" ),然后连接。

但是最后的操作只涉及Integer ,所以以前的规则不适用。 而不是连接,它做了一个补充。 但是要添加两个Integer ,它会将对象( Integer )转换为原始值(整数),如果Integer为空,这是不可能的。 这就是为什么你得到一个NullPointerException

似乎是一个自动拆箱的情况。 如果你有两个Integerfirstsecond ,那么它们的加法结果是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 
Interesting Posts