49
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只在最后一行收到一个?

4

6 回答 6

60

您的代码使用了两种不同的加法运算符。前三行使用字符串连接,而最后一行使用数字加法

字符串连接被明确定义null"null"

  • 如果引用为null,则将其转换为字符串"null"(四个 ASCII 字符null)。

因此没有NPE。

将两个Integer对象加在一起需要将它们拆箱。这导致null引用被取消引用,从而导致 NPE:

  • 如果r为空,拆箱转换会抛出一个NullPointerException
于 2013-01-26T16:32:31.767 回答
17

请注意,前三个+运算符用法涉及字符串连接。只有最后一个是实际的数字sum。当涉及字符串连接时(涉及s变量),Java 编译器使用一些巧妙的技巧来提高性能。它将+运算符替换为StringBuilder. 例如,您的第一行被翻译为:

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

StringBuildernull- 友好的,所以无论您作为参数传递什么,它都会很好地用"null"字符串替换它。

最后一行的情况有所不同。在那里你引用了两个Integer对象。JVM 在这里唯一能做的就是将它们拆箱 ( i.intValue()) 并进行实际计算。拆箱null原因NullPointerException

于 2013-01-26T16:27:53.963 回答
5

+任何与 a的连接(运算符)都会String导致 a String。每个操作数首先转换为字符串(使用toString()或使用 value "null"),然后连接。

但是最后一个操作Integer只涉及 s,所以前面的规则不适用。它不是串联,而是加法。但是要添加两个Integers,它会将对象 ( s) 转换为原始值 (int),如果 s为 null Integer,则这是不可能的。Integer这就是为什么你得到一个NullPointerException.

于 2013-01-26T16:29:23.747 回答
1

似乎是自动拆箱的情况。如果你有两个Integersfirstsecond,那么它们相加的结果就是first.intValue() + second.intValue()。由于它们都为空,因此会导致 NPE。

于 2013-01-26T16:28:07.783 回答
0

看看你程序的字节码。您会注意到您的 null 对象正在作为参数传递给 PrintStream.print() 方法。print() 方法的源代码使用 String.valueOf() 如下所示:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}
于 2013-01-26T16:41:20.803 回答
0

应该注意的是,这个问题的答案从输出中应该是显而易见的:

C:\Temp>java Test
nullnull
nullnull
nullnull
NullPointerException
于 2013-02-01T17:51:26.033 回答