なぜ次のように機能しますか? NullPointerException
がスローされることを期待します。
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
JLS 5、セクション15.18.1.1JLS 8§15.18.1 "文字列連結演算子+" 、 JLS 8、§5.1.11 "文字列変換" につながるため、失敗:
...参照値のみを考慮する必要があります。 参照がnullの場合、文字列「null」に変換されます(4つのASCII文字n、u、l、l )。それ以外の場合、変換は、引数なしで参照されるオブジェクトのtoStringメソッドの呼び出しによるかのように実行されます。ただし、toStringメソッドの呼び出し結果がnullの場合、代わりに文字列「null」が使用されます。
バイトコードを見てみましょう!コンパイラーはコードを受け取ります。
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
代わりにこれを書いたかのようにバイトコードにコンパイルします:
String s = null;
s = new StringBuilder(String.valueOf(s)).append("hello").toString();
System.out.println(s); // prints "nullhello"
( javap -c
)を使用して自分で行うことができます
StringBuilder
のappendメソッドはすべてnullを適切に処理します。この場合、null
が最初の引数であるため、StringBuilderには任意の参照型を受け取るコンストラクタがないため、代わりにString.valueOf()
が呼び出されます。
代わりにs = "hello" + s
を実行した場合、同等のコードは次のようになります。
s = new StringBuilder("hello").append(s).toString();
この場合、appendメソッドはnullを受け取り、thenがString.valueOf()
にそれを委任します。
注:文字列の連結は、実際には、コンパイラが実行する最適化を決定するまれな場所の1つです。そのため、「完全に同等の」コードはコンパイラごとに異なる場合があります。この最適化は JLS、セクション15.18.1.2 で許可されています:
繰り返し文字列連結のパフォーマンスを向上させるために、Javaコンパイラは、StringBufferクラスまたは同様の手法を使用して、式の評価によって作成される中間Stringオブジェクトの数を減らすことができます。
上記の「同等のコード」を決定するために使用したコンパイラーは、Eclipseのコンパイラーecjでした。
Java言語仕様のセクション 5.4 および 15.18 を参照してください。
引数の1つが文字列の場合、文字列変換はバイナリ+演算子のオペランドにのみ適用されます。この単一の特殊なケースでは、+への他の引数は文字列に変換され、2つの文字列の連結である新しい文字列は+の結果です。文字列変換は、文字列連結+演算子の説明内で詳細に指定されます。
そして
1つのオペランド式のみがString型の場合、実行時に文字列を生成するために、他のオペランドで文字列変換が実行されます。結果は、2つのオペランド文字列の連結であるStringオブジェクト(式がコンパイル時の定数式(§15.28)でない限り、新しく作成された)への参照です。新しく作成された文字列では、左側のオペランドの文字が右側のオペランドの文字に先行します。 String型のオペランドがnullの場合、そのオペランドの代わりに文字列「null」が使用されます。
2行目は次のコードに変換されます。
s = (new StringBuilder()).append((String)null).append("hello").toString();
Appendメソッドは、null
引数を処理できます。
「null」を使用していないため、例外は発生しません。 NullPointerが必要な場合は、
String s = null;
s = s.toString() + "hello";
そして、あなたがやりたいことは
String s = "";
s = s + "hello";
これは、Java APIの String.valueOf(Object)
メソッドで指定された動作です。連結を行う場合、valueOf
を使用してString
表現を取得します。オブジェクトがnull
の場合は特別なケースがあり、その場合は文字列"null"
が使用されます。
public static String valueOf(Object obj)
Object引数の文字列表現を返します。
パラメータ:obj-オブジェクト。
返却値:
引数がnullの場合、「null」に等しい文字列。それ以外の場合、obj.toString()の値が返されます。