18

2つの質問があります:

public static void main(String[] args) {
  String s1 = "bla";
  String s2 = "b" +"l" + "a";
  String s3 = "b".concat("l").concat("a");

  if(s1 == s2) 
        System.out.println("Equal");
  else
        System.out.println("Not equal");
  if(s1 == s3) 
        System.out.println("Equal");
  else
        System.out.println("Not equal");
}
  • なぜs1s2は同じオブジェクトを指しているのに、s1とはそうでs3はないのですか?(キーワードの使用法はありませんnew)。

  • ユーザーから文字列を取得し、上記のコードに次の行を追加すると、次のようになります。

    BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
    String name=in.readLine();
    if(name.equals("test"))
        s1 = s1 + "xyz";
    

    ユーザーxyzがプログラムに入ると印刷さNot equalれ、ユーザーが別のものを入力するとプログラムが出力しますEqual。これは、プログラム全体の実行によってプールが変化することを意味しますか?オプティマイザーはコンパイル時に機能し、引き続き機能しruntimeますか?

4

3 に答える 3

15

s1とs2が同じオブジェクトを指しているのに、s1とs3はそうではないのはなぜですか?(新しいキーワードの使用はありません)。

連結はコンパイル時に発生するため、完成した文字列は最初の例と同じように定数プールに入れられます。これは、コンパイラに「知られている」特殊なケースです。これは、実際には、このように複数の行に連結された長い文字列でも、単純な文字列定数と同じパフォーマンスの向上のメリットを享受できることを意味します。

2番目の例では、実行時に計算を実行しているため、定数プールの一部にはなりません。

ただし、JLSでは、文字列定数プールに入れることができるものとできないものの詳細が意図的にあいまいになっているため、さまざまな実装がさまざまな方法で最適化される可能性があることに注意してください。そこに何を入れる必要があるかについて特定のルールを指定しますが、実装間で一貫しているこの動作に依存しないでください。

于 2013-01-21T21:38:16.180 に答える
9

s1とs2が同じオブジェクトを指しているのに、s1とs3はそうではないのはなぜですか?(新しいキーワードの使用はありません)。

StringJavaではがであるためImmutable、文字列クラスのどのメソッドも新しいStringオブジェクトを返します(ただし、いくつかの例外があります。1つはsubstringメソッドです)。したがってconcat、メソッドは新しい文字列を作成します。この文字列はヒープに送られ、定数プールには追加されません。

s1とに関する限りs2、両方の文字列はコンパイル時に既知であるため、同じ文字列リテラルです。

2番目の文字列の連結操作に注意してください:-

String s2 = "b" +"l" + "a";

はコンパイル時に評価され、結果は最初の文字列と同じであることがわかっており、定数プールに1つのエントリが作成されます。

于 2013-01-21T21:37:27.373 に答える
3

コンパイラが文字列プールを使用する場合もあれば(コンパイラにとって実行時の文字列の値が明らかな場合)、そうでない場合もあります。

実際、コードはプールを使用するかどうかに依存するべきではありません。

常にmainを実行できるとは限らないため、Stringがプールから使用されているかどうかを確認したい場合は、javapを使用してコードを逆コンパイルできます。リストは比較的自明です。

于 2013-01-22T05:33:56.837 に答える