次のコードを検討してください。
String first = "abc";
String second = new String("abc");
new
キーワードを使用すると、Java はabc
String
再度作成しますよね? String
これは通常のヒープまたはプールに格納されますか? プールString
で終わるのは何秒ですか?String
次のコードを検討してください。
String first = "abc";
String second = new String("abc");
new
キーワードを使用すると、Java はabc
String
再度作成しますよね? String
これは通常のヒープまたはプールに格納されますか? プールString
で終わるのは何秒ですか?String
new
キーワードを使用すると、新しいString
オブジェクトが作成されます。オブジェクトは常にヒープ上にあることに注意してください。文字列プールは、ヒープとは別のメモリ領域ではありません。
文字列プールはキャッシュのようなものです。これを行う場合:
String s = "abc";
String p = "abc";
String
その場合、Java コンパイラは 1 つのオブジェクトだけを作成するほどスマートでありs
、p
両方が同じ String オブジェクトを参照します。これを行う場合:
String s = new String("abc");
次にString
、リテラルを表すプール内に 1 つのオブジェクトが存在し、プール内ではなく、プールされたオブジェクトのコンテンツのコピーを含む"abc"
別のオブジェクトが存在します。String
は Java では不変であるためString
、これを行っても何も得られません。呼び出しnew String("literal")
は Java ではまったく意味がなく、不必要に非効率的です。
オブジェクトintern()
を呼び出すことができることに注意してください。String
これにより、String
オブジェクトがまだ存在しない場合はプールに配置され、プールされた文字列への参照が返されます。(既にプールにある場合は、既に存在するオブジェクトへの参照を返すだけです)。詳細については、そのメソッドの API ドキュメントを参照してください。
文字列のインターン(ウィキペディア)も参照してください。
bytecodeでは、最初の割り当ては次のとおりです。
コード: 0: ldc #2; //文字列abc 2: アストア_1
一方、2番目は次のとおりです。
3: 新しい #3; //クラス java/lang/String 6: 複製 7: ldc #2; //文字列abc 9: 特殊呼び出し #4; //メソッド java/lang/String."":(Ljava/lang/String;)V
したがって、最初はプール (位置 #2) にあり、2 番目はヒープに格納されます。
編集
CONSTANT_String_info
インデックスを U2 (16 ビット、符号なし) として格納するため、プールには最大で参照を含めることができ2**16
ます65535
。ここで気になる場合は、 JVM の制限を増やしてください。
コードが文字列リテラルを作成するたびに
例えば:
String str="Hello"; (string literal)
JVM は最初に文字列リテラル プールをチェックします。文字列がプールに既に存在する場合は、プールされたインスタンスへの参照が返されます。文字列がプールに存在しない場合、新しい String オブジェクトがインスタンス化され、プールに配置されます。文字列は不変であり、データの破損を恐れずに共有できるため、Java はこの最適化を行うことができます。
new String(foo) を使用する必要があるのは、== を壊したいときだけです。これは奇妙なケースです。
String mystring;
{
String source = getSomeHeinouslyLargeString();
mystring = new String(source.substring(1,3));
}