73

String プールの奇妙な動作について質問があります。==等しい文字列を比較して、それらがプールにあるかどうかを確認するために使用しています。

public class StringPoolTest {
  public static void main(String[] args) {
    new StringPoolTest().run();
  }

  String giveLiteralString() {
    return "555";
  }

  void run() {
    String s1 = giveLiteralString() + "";
    System.out.println("555" == "555" + "");
    System.out.println(giveLiteralString() == giveLiteralString() + "");
  }
}

出力は次のとおりです。

true
false

これは私にとって大きな驚きです。誰でもこれを説明できますか?これについては、コンパイル時に何かが起こっていると思います。しかし、なぜ""String に追加しても違いが生じるのでしょうか?

4

4 に答える 4

110
"555" + ""

コンパイル時の定数ですが、

giveLiteralString() + ""

そうではありません。したがって、前者は文字列定数 "555" だけにコンパイルされ、後者は実際のメソッド呼び出しと連結にコンパイルされ、新しい String インスタンスが生成されます。


JLS §3.10.5 (文字列リテラル) も参照してください。

実行時に連結によって計算された文字列は新しく作成されるため、区別されます。

于 2013-07-08T11:16:03.603 に答える
32

この行を逆コンパイルした後

System.out.println("555" == "555" + "");

このバイトコードを取得しました

    LINENUMBER 8 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ICONST_1
    INVOKEVIRTUAL java/io/PrintStream.println(Z)V
    ...

これはと同等です

  System.out.println(true);

つまり、式"555" == "555" + ""は boolean にコンパイルされtrueます。

このgiveLiteralString() == giveLiteralString() + ""バイトコードをビルドした javacの場合

    LINENUMBER 8 L0
    INVOKESTATIC Test1.giveLiteralString()Ljava/lang/String;
    NEW java/lang/StringBuilder
    DUP
    INVOKESTATIC Test1.giveLiteralString()Ljava/lang/String;
    INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
    IF_ACMPNE L1
    ...

これはと同等です

if (giveLiteralString() == new StringBuilder(giveLiteralString()).append("").toString()) {
...

ここでは 2 つの異なるオブジェクトを比較しているため、常に false が生成されます。

于 2013-07-08T11:24:09.273 に答える