8

Java の文字列プールに関するこの質問を読み 、文字列プールの基本的な概念は理解していますが、動作はまだ理解していません。

最初: 値を直接割り当て、s1 と s2 の両方がプール内の同じオブジェクトを参照する場合に機能します

String s1 = "a" + "bc";
String s2 = "ab" + "c";
System.out.println("s1 == s2? " + (s1 == s2));

しかし、文字列 s1+="d" を変更すると、プールには文字列オブジェクト "abcd" が必要ですか? 次に、s2+="d" を変更すると、プール内の文字列オブジェクト "abcd" が検出され、そのオブジェクトが s2 に割り当てられるはずです。しかしそうではなく、それらは同じオブジェクトを参照していません。何故ですか?

String s1 = "abc";
String s2 = "abc";
System.out.println("s1 == s2? " + (s1 == s2));

s1 += "d";                  
s2 += "d";
System.out.println("s1 == s2? " + (s1 == s2));
4

6 に答える 6

7

文字列を呼び出すと、文字列がプールされることが保証されString.intern()ます。

String s1 = "abcd".intern();
String s2 = "abc";
s2 += "d";
s2 = s2.intern();
s1 == s2 // returns true

コンパイラが定数を検出すると、文字列リテラルを最適化してプールするのに十分スマートです。つまり、次のようになります。

String s1 = "abcd";
String s2 = "abcd";
s1 == s2 // returns true

Java 言語仕様は次のように述べています。

各文字列リテラルは、クラス String (§4.3.3) のインスタンス (§4.3.1、§12.5) への参照 (§4.3) です。文字列オブジェクトには定数値があります。文字列リテラル (より一般的には、定数式の値である文字列 (§15.28)) は、メソッド String.intern を使用して、一意のインスタンスを共有するために「インターン」されます。

の場合s2 += "d"、コンパイラはあなたほど賢くなく、プールされただけ"d"です。

于 2013-01-23T21:51:56.757 に答える
3

これについては確信が持てないので、これは推測にすぎませんが、最初の例 (インラインで何が起こっているのかがかなり明白) でコンパイラのトリックが行われている可能性があると思いますが、引っ張るほど賢くはありません。 2 番目の例ではオフになっています (それほど明白ではありません)。

私が正しければ、コンパイラは"a" + "bc"コンパイル時に"abc"それを見て単純に圧縮するか、2行を見て文字列が使用されることを認識してプールしています。私は前者に賭けます..

すべての文字列が必ずしもプールされるわけではありません。

于 2013-01-23T21:55:58.547 に答える
2

String#intern()のドキュメントを参照してください。そこの最後の行には次のように記載されています。

すべてのリテラル文字列と文字列値の定数式はインターンされます。

あなたの+=例はリテラル文字列でも文字列値の定数式でもないため、文字列プールには入れられません。

于 2013-01-23T22:05:08.200 に答える
2

コンパイラは定数評価を実行できますが、値を変更する場合は実行できません

final代わりに以下を試して、どちらかの変数からドロップするとどうなるかを確認してください。

final String s1 = "abc";
final String s2 = "abc";
System.out.println("s1 == s2? " + (s1 == s2));

String s3 = s1 + "d";                  
String s4 = s2 + "d";
System.out.println("s3 == s4? " + (s3 == s4));
于 2013-01-23T22:05:36.277 に答える
0

これは私の推測です:

文字列 s1 = "a" + "bc"; 文字列 s2 = "ab" + "c";

これらはコンパイル時に同じ文字列を生成すると判断されるため、両方に対して1つのオブジェクトのみが作成されると思います。

ただし、両方に「d」を追加すると、これは両方の文字列に対して個別に行われます(リアルタイムで行われるため、例外が中断するなどの可能性があるため、事前に行うことはできません)。自動的に 1 つのオブジェクトを参照するようにはなりません。

于 2013-01-23T21:55:45.783 に答える
0

ここで何が起こると思います: 1. for String s1 = "a" + "bc"; 文字列 s2 = "ab" + "c"; Java コンパイラは、s1 と s2 のリテラル値が同じであることを認識できるほどスマートであるため、コンパイラはそれらを文字列プール内の同じリテラル値にポイントします。

  1. s1 += "d" の場合。
    s2 += "d";

s1 と s2 が同じ値になるかどうかをコンパイラが知る方法はありません。実行時に String.intern() を呼び出さない限り、jvm は文字列リテラル プールをチェックして値が既に存在するかどうかを確認しません。

于 2013-01-23T22:11:59.093 に答える