次のコードを検討してください。
String first = "abc";
String second = new String("abc");
new
キーワードを使用する場合、Javaはabc
String
を再び正しく作成しますか?これは通常のヒープまたはString
プールに保存されますか?String
sはString
プールでいくつ終了しますか?
new
キーワードを使用すると、新しいString
オブジェクトが作成されます。オブジェクトは常にヒープ上にあることに注意してください-文字列プールは、ヒープとは別のメモリ領域ではありません。
文字列プールはキャッシュのようなものです。これを行う場合:
_String s = "abc";
String p = "abc";
_
Javaコンパイラは、1つのString
オブジェクトを作成するのに十分スマートであり、s
とp
は両方とも同じStringオブジェクトを参照します。これを行う場合:
_String s = new String("abc");
_
その後、プールにはリテラル変数_"abc"
_を表す1つのString
オブジェクトが存在し、プールされたオブジェクトのコンテンツのコピーを含む、プールではなく別のString
オブジェクトが存在します。 String
はJavaでは不変であるため、これを行っても何も得られません。 new String("literal")
の呼び出しは、Javaで意味をなさないため、不必要に非効率的です。
String
オブジェクトでintern()
を呼び出すことができることに注意してください。これにより、String
オブジェクトがまだプールにない場合はプールに配置され、プールされた文字列への参照が返されます。 (既にプール内にあった場合は、すでにそこにあったオブジェクトへの参照を返すだけです)。詳細については、そのメソッドのAPIドキュメントを参照してください。
String interning (Wikipedia)も参照してください。
bytecodeでは、最初の割り当ては次のとおりです。
コード: 0:ldc#2; // String abc 2:astore_1
一方、2番目は:
3:新しい#3; // class Java/lang/String 6:dup 7:ldc#2; // String abc 9:invokespecial#4; //メソッドJava/lang/String。 "" :( Ljava/lang/String;)V
したがって、1つ目はプール(位置#2)にあり、2つ目はヒープに格納されます。
[〜#〜] edit [〜#〜]
CONSTANT_String_info
インデックスをU2として保存 (16ビット、符号なし)プールには最大2**16
= 65535
参照。気にする場合 ここではJVMのより多くの制限 。
コードが文字列リテラルを作成するたびに
例えば:
String str="Hello"; (string literal)
jVMは最初に文字列リテラルプールをチェックします。文字列が既にプールに存在する場合、プールされたインスタンスへの参照が返されます。文字列がプールに存在しない場合、新しいStringオブジェクトがインスタンス化され、プールに配置されます。 Javaは文字列が不変であり、データ破損の恐れなく共有できるため、この最適化を行うことができます
String strObject = new String("Java");
そして
String strLiteral = "Java";
どちらの式もStringオブジェクトを提供しますが、両者には微妙な違いがあります。 new()演算子を使用してStringオブジェクトを作成すると、常にヒープメモリに新しいオブジェクトが作成されます。一方、文字列リテラル構文を使用してオブジェクトを作成する場合、例えば「Java」、既存のオブジェクトが既に存在する場合、ストリングプール(最近のJavaリリースでヒープスペースに移動されるようになったPerm genスペースのストリングオブジェクトのキャッシュ)から既存のオブジェクトを返すことがあります。
New String(foo)を使用する必要があるのは、==を破りたい場合(これは奇妙なケースです)、またはfooが、寿命が限られている非常に大きな文字列の部分文字列である場合などです。
String mystring;
{
String source = getSomeHeinouslyLargeString();
mystring = new String(source.substring(1,3));
}
String first = "abc";
String second = new String("abc");
最初の場合、プールに作成されるオブジェクトは1つだけです。 2番目のケースでは、2つのオブジェクトが1つをプール内に作成し(以前にプール内に存在しなかった場合)、もう1つをヒープ内に作成します。
二重引用符ex: "abc"を使用して値を渡す場合、プールにオブジェクトを作成し、それを文字列コンストラクターに渡して、ヒープに同じ値を持つ新しいオブジェクトを作成します。
文字列コンストラクターを見た場合、文字列を受け入れることがわかります。その文字列は何ですか?作成する前に、その文字列オブジェクトは何ですか。これは、文字列定数プールに格納されたオブジェクトに他なりません。
遅いですが、これに出くわした人にとっては便利かもしれません:
String first = "abc";
//One instance object in pool created. Instance variable “first” refers/points to pooled object
String second = new String("abc");
//One instance object in heap created. Object in pool creation step will be skipped on account of first statement.
したがって、合計2つのインスタンスオブジェクトが作成されます。プールに1つ、ヒープに1つ
詳細な説明
String first = "abc";
ここでは、コンテンツ「abc」を含む文字列オブジェクトがプールに作成されます。インスタンス変数「first」は、コンテンツ「abc」を持つプールオブジェクトを指します。
String second = new String( "abc");
ここでは、コンテンツ「abc」を持つ別の文字列オブジェクトがヒープに作成されます。インスタンス変数「second」は、コンテンツ「abc」を持つヒープオブジェクトを指します。プール内のコンテンツ「abc」の作成を含む文字列オブジェクトは、最初のステートメントのためにスキップされます。以下の理由。
理由
前の文(String first = "abc";)が同じコンテンツではない場合、通常「new」キーワードを使用すると、2つの文字列オブジェクトがヒープ(プール外)とプール(サブセットエリア)に作成されます。ヒープの)。また、インスタンス変数「second」は、オブジェクトがプール内にあるかどうかに関係なく、ヒープオブジェクトのみを指す必要があります。
これで、新しいString( "abc")と同じコンテンツを持つ前のステートメント(String first = "abc";)が存在するため、1つのオブジェクト(コンテンツ "abc")のみがプールに保持されます。したがって、最初のステートメントのために、2番目のステートメントには2ではなく1つのオブジェクトのみが作成され、そのオブジェクトはヒープ内にあります。プールオブジェクトの作成はスキップされます。
//Additional Test on the concept
System.out.println(first==second); //returns false. Because first points to pool object while second points to heap object. And both objects are different (on account of different memory locations).
second = second.intern(); //After interning, second now points to pool object. Note: intern is used so that reference variable points to pool area object and not heap object. Clearly it is applicable when we use new keyword.
System.out.println(first==second); //returns true. Because now both first and second objects now points to same pool object.