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
を受け取るのですか?
あなたのコードは2つの異なる 加法演算子 を利用しています。最初の3行は 文字列連結 を使用し、最後の行は 数値加算 を使用します。
文字列の連結は null
を"null"
に変換するように明確に定義されています :
- 参照が
null
の場合、文字列"null"
に変換されます(4つのASCII文字n
、u
、l
、l
)。
したがって、NPEはありません。
2つのInteger
オブジェクトを一緒に追加するには、それらが nboxed である必要があります。これにより、null
参照が逆参照され、NPEが発生します。
r
がnullの場合、ボックス化解除の変換によりNullPointerException
がスローされます
最初の3つの_+
_演算子の使用には、文字列の連結が含まれることに注意してください。最後のものだけが実際の数値です合計。文字列の連結が含まれる場合(s
変数が含まれる場合)、Javaコンパイラは、パフォーマンスを向上させるために巧妙なトリックを使用します。_+
_演算子をStringBuilder
。たとえば、最初の行は次のように変換されます。
_StringBuilder tmp = new StringBuilder();
tmp.append(s);
tmp.append(i);
System.out.println(tmp);
_
StringBuilder
はnull
に適しているため、引数として何を渡しても、_"null"
_文字列にうまく置き換えられます。
最後の行では状況が異なります。そこで、2つのInteger
オブジェクトを参照します。ここでJVMが実行できるのは、それらをボックス化解除して(i.intValue()
)、実際の計算を実行することだけです。 null
を開封すると、NullPointerException
が発生します。
String
を持つものを連結(_+
_演算子)すると、String
になります。すべてのオペランドは、最初に文字列に変換され(toString()
を使用するか、値_"null"
_を使用)、次に連結されます。
ただし、最後の操作にはInteger
sのみが含まれるため、前のルールは適用されません。連結の代わりに、加算を行います。ただし、2つのInteger
sを追加するには、オブジェクト(Integer
s)をプリミティブ値(int)に変換します。これは、Integer
がnullの場合は不可能です。そのため、NullPointerException
を取得します。
自動開封の場合のようです。 2つのInteger
s first
とsecond
がある場合、それらの加算の結果はfirst.intValue() + second.intValue()
になります。両方ともnullであるため、結果としてNPEになります。
この質問への答えは、出力から明らかであるはずであることに注意してください。
C:\Temp>Java Test
nullnull
nullnull
nullnull
NullPointerException
プログラムのバイトコードを見てください。 nullオブジェクトがパラメータとしてPrintStream.print()メソッドに渡されていることに気付くでしょう。 print()メソッドのソースコードは、以下に示すようにString.valueOf()を使用します。
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}