jvm
メモリの最適化のために作成する場合、キーワードstring pool
を使用して文字列を作成するたびに新しいオブジェクトが作成されるのはなぜですか?new
string pool
7 に答える
...なぜ Java は
new
、文字列プールに存在するにもかかわらず、キーワードを使用して文字列を作成するたびに新しいオブジェクトを作成するのですか?
あなたがはっきりと言ったからです!new
オペレーターは常に新しいオブジェクトを作成します。 JLS 15.9.4は次のように述べています。
「クラス インスタンス作成式の値は、指定されたクラスの新しく作成されたオブジェクトへの参照です。式が評価されるたびに、新しいオブジェクトが作成されます。」
記録として、ほとんどの場合、呼び出すのは間違いnew String(String)
です...しかし、あいまいなケースでは、それが役立つ場合があります。equals
を返しtrue
たり==
与えたりする文字列が必要になることも考えられますfalse
。電話new String(String)
するとそれが得られます。
古いバージョンの Java の場合substring
、trim
およびおそらく他のString
メソッドは、元のバッキング ストレージを共有する文字列を提供します。特定の状況下では、これによりメモリ リークが発生する可能性があります。new String(str.trim())
たとえば、呼び出しは、トリミングされた文字列の新しいコピーを作成するという犠牲を払って、そのメモリ リークを防ぎます。コンストラクターはString(String)
、新しいバッキング配列の割り当てと、新しいString
オブジェクトの提供を保証します。
のこの動作は、Java 7substring
で変更されました。trim
プリミティブなスタイルの宣言を提供するため、およびパフォーマンス デザイナーのために String リテラルが導入されました。
ただし、new
キーワードを使用すると、定数プールではなくヒープにオブジェクトを明示的に作成します。
オブジェクトがヒープ上に作成されると、そのメモリを互いに共有する方法がなく、定数プールとは異なり、それらは完全に見知らぬものになります。
ヒープと定数プールの間のこの障壁を破ることString interning
は、あなたを助けるでしょう.
文字列インターニングは、不変である必要がある、個別の文字列値のコピーを 1 つだけ格納する方法です。
定数プールもヒープの小さな部分であり、メモリの共有が利用できる場合にいくつかの追加の利点があることに注意してください。
あなたが書くとき
String str = new String("mystring");
次に、作成した他のオブジェクトと同じように、ヒープに文字列オブジェクトを作成します。文字列リテラル "mystring" は、文字列定数プールに格納されます。
Javadocから:
最初は空である文字列のプールは、クラス String によってプライベートに維持されます。
intern メソッドが呼び出されたときに、equals(Object) メソッドによって決定されたこの String オブジェクトと等しい文字列がプールにすでに含まれている場合、プールからの文字列が返されます。それ以外の場合は、この String オブジェクトがプールに追加され、この String オブジェクトへの参照が返されます。
したがって、任意の 2 つの文字列 s および t について、s.intern() == t.intern() は、s.equals(t) が true である場合にのみ true になります。
文字列プーリングを利用するString#intern
には、new の代わりに使用する必要があります。
ガベージコレクションを強制するために!String が一度だけ必要な場合は、それをメモリに保持しても意味がありません (ほぼ永久に。これは定数プールの Stringsの場合です)。定数プールにない文字列は、他のオブジェクトと同様に GC できます。そのため、頻繁に使用される文字列のみを定数プールに保持する必要があります (リテラルを使用するかインターンすることにより)。
次のオブジェクトは String プールに格納されます。
String s = "hello";
そして、次のオブジェクトは (文字列プールではなく) ヒープに格納されます。
String s = new String ("hello")
文字列リテラル ( String s = "string";
) の形式で作成された文字列は文字列プールに格納されますが、 new ( を使用して文字列コンストラクターを呼び出して作成されString s = new String("string");
た文字列は文字列プールに格納されません。