28

これらのStackoverflowの質問で説明されているように:質問1質問2 「文字列リテラル」は次の場合にインターンされることを理解しています。

String s = "abc"; 

また、JVMは、次の場合に、文字列プールの既存のオブジェクトを使用する代わりに、新しい文字列オブジェクトを作成します。

String s = new String("abc");

しかし、次の2つの類似したステートメントを読んだ後、私は疑問を持っています。

コンパイラが文字列リテラルを検出すると、プールをチェックして、同一の文字列がすでに存在するかどうかを確認します。一致するものが見つかった場合、新しいリテラルへの参照は既存の文字列に向けられ、新しい文字列リテラルオブジェクトは作成されません。

この場合、キーワード「new」のため、実際にはわずかに異なる動作になります。このような場合でも、文字列リテラルへの参照は定数テーブル(文字列リテラルプール)に配置されますが、キーワード「new」に到達すると、JVMは実行時に新しい文字列オブジェクトを作成する必要があります。定数テーブルからのものを使用するのではなく。

したがって、上記の定義に基づいて「new」を使用してオブジェクトを作成するときに、非プールメモリとプールメモリにも参照を配置するとします。これを行うときに、JVMも同じ参照を返す必要がありますか?

String one = new String("test");
String two = "test";

System.out.println(one.equals(two)); // true
System.out.println(one == two);      // false

文字列リテラルを宣言するとき、String three = "test";それはすでにプールに存在するのでしょうか?したがって、同じ参照を返し、trueを出力する必要がありますか?newまたは、前のステートメントは、それらがプールメモリに配置されるが、演算子が使用されるときに単にスキップされることを意味しますか?

4

5 に答える 5

33

多分これはあなたの理解を助けるでしょう:

String literal = "test";
String one = new String(literal);
String two = "test";

System.out.println(literal == two); //true
System.out.println(one == two); //false

あなたが投稿した例では:

String one = new String("test");
String two = "test";

コンストラクターに渡される参照は、インターンのためにString(String)参照と同じ値になります。twoただし、文字列自体(これらの2つの参照によって参照される)は、参照に割り当てられる新しいoneオブジェクトを構築するために使用されます。

この例ではString、値「test」で作成された2つのがあります。1つは定数プールに保持され、式でリテラルを使用するたびに参照"test"され、もう1つは「new」演算子によって作成されてに割り当てられます。参照one

編集

おそらくあなたはこの声明について混乱しています:

コンパイラが文字列リテラルを検出すると、プールをチェックして、同一の文字列がすでに存在するかどうかを確認します。

これは、より明確に次のように記述される場合があることに注意してください。

コンパイラが文字列リテラルを検出すると、同じ文字列がプールにすでに存在するかどうかを確認します。

文字列は、明示的にインターンされた場合、またはクラスでリテラルを使用した場合にのみプールに入れられます。したがって、たとえば、次のシナリオがある場合:

String te = "te";
String st = "st";

String test = new String(te) + new String(st);

次に、aStringは値とともに存在しますが、リテラルが発生したことtestがないため、上記の文字列はプールに存在し"test"ません。

于 2013-01-04T03:23:46.620 に答える
8
    //Creates a new object even if one exists in the pool
    String s1 = new String("Tendulkar");

    // makes a new object string and then the reference is available to the pool
    String s2 = s1.intern();

    //this object is not created but references the address present in the pool
    String s3 = "Tendulkar";

    System.out.print(s1==s2); // results in false
    System.out.print(s2==s3); //very very true !!!
于 2013-11-16T17:51:11.010 に答える
2

"abc"コンパイル/クラスロード時にオブジェクトを定数プールに入れ、実行時new String()に新しいオブジェクトを作成します。両方もそうですが、フェーズは異なります。new String("abc")

于 2013-01-04T09:12:48.093 に答える
2

あなたの質問 :

したがって、上記の定義に基づいて「new」を使用してオブジェクトを作成するときに、非プールメモリとプールメモリにも参照を配置するとします。これを行うと、JVMも同じ参照を返す必要がありますか?:

回答:newキーワードを使用して新しい文字列オブジェクトを作成すると、生成されるアドレスは、文字列定数のプールされたアドレスではなく、ヒープアドレスになります。そして、両方のアドレスが異なります。

質問

String one = new String("test");
String two = "test";

System.out.println(one.equals(two)); // true
System.out.println(one == two);      // false

前のステートメントは、それらがプールメモリに配置されるが、新しい演算子が使用されるときに単にスキップされることを意味しますか?

回答:はい、あなたの仮定は正しいです。プログラマーがnewキーワードを使用すると、JVMは文字列定数プールを単に無視し、ヒープに新しいコピーを作成します。したがって、両方のアドレスは同じではありません。

于 2013-12-10T07:06:53.683 に答える
0

文字列リテラルの作成

  1. 文字列リテラルを作成するたびに、JVMは最初に文字列定数プールをチェックします

  2. 文字列がすでにプールに存在する場合、プールされたインスタンスへの参照が返されます

  3. 文字列がプールに存在しない場合、新しい文字列インスタンスが作成され、プールに配置されます

例、

    String s1 = "Welcome";
    String s2 = "Welcome"; //will not create new instance

文字列リテラルと文字列オブジェクト

    String str1 = "Hello World!!";
    String str2 = "Hello World!!";
    System.out.println(str1 == str2);// true

文字列リテラルstr2が作成されると、文字列「HelloWorld」は再度作成されません。代わりに、str1です。文字列は文字列定数プールにすでに存在するため、文字列が再利用されます。

str1とstr2の両方が同じものを参照しているため

    String str3 = new String("Hello World!!");
    String str4 = new String("Hello World!!");
    System.out.println(str3 == str4); // false

この場合、新しいStringオブジェクトが作成され、str3とstr4によって別々に参照されます。したがって、str3==str4はfalseです。プール内の文字列、str1==str2はtrueです。

于 2019-12-05T03:12:01.457 に答える