Javaは、フードの下で弦のフライ級パターンをどのように実装していますか?
-
04-10-2019 - |
質問
文字列の2つのインスタンスがあり、それらが等しい場合、Javaでは同じメモリを共有します。これはフードの下でどのように実装されていますか?
編集:私のアプリケーションでは、多数の文字列オブジェクトを使用していますが、その多くは同一です。カスタムフライ級実装の作成を避けるために、Java String Constant Poolを使用する最良の方法は何ですか?
解決
のソースコードを見てください java.lang.String
(Java API全体のソースはJDKの一部です)。
要約するには:文字列はのサブシーケンスを包みます char[]
. 。その支援 char[]
変更されることはありません。これは、これを漏らしたり捕まえたりすることによって達成されます char[]
外 String
クラス。しかし、いくつか Strings
同じものを共有できます char[]
(の実装を参照してください String.substring
).
他の答えで説明されているように、インターンのメカニズムもあります。
他のヒント
文字列の2つのインスタンスがあり、それらが等しい場合、Javaでは同じメモリを共有します
これは実際には100%真実ではありません。
このブログ投稿はまともな説明です なぜこれがそうであるのか、そして何が 文字列定数プール は。
文字列リテラルはJavaでインターンされているため、複数の参照を持つ文字列オブジェクトは1つだけです(等しい場合、常にそうではありません)。 java.netの記事を参照してください インターンについてすべて() 詳細については。
セクションには良い例/説明もあります 3.10.5文字列リテラル 文字列がインターンされているときとそれらが明確になる時期について語るJLSの。
それは必要ではありません。例:
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true
しかし:
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false
これで、2番目のフォームが落胆しています。一部の(私を含む)と思う String
パブリックコンストラクターさえ持ってはいけません。上記のより良いバージョンは次のとおりです。
String s1 = new String("hello").intern();
String s2 = new String("hello").intern();
System.out.println(s1 == s2); // true
明らかに、あなたは定数のためにこれをする必要はありません String
. 。それは実例です。
これについての重要なポイントは、あなたが合格した場合です String
または、あなたが頼ることができない関数からそれを取得します String
であること 正規. 。 a 正規 Object
この平等を満たす:
a.equals(b) == b.equals(a) == (a == b)
非非のためにnull
インスタンス a
, b,
与えられた Class
.
編集された質問に答えるために、Sun jvmsには -XX:+StringCache
私の観察では、文字列重いアプリケーションのメモリフットプリントを大幅に減らすことができます。
それ以外の場合は、弦をインタリングするオプションがありますが、私はそれについて注意してください。非常に大きく、もはや参照されていない文字列は、JVMの寿命にメモリを使用します。
編集(コメントに応じて):最初にStringCacheオプションについて知りました ここ:
-XX:+StringCacheは、一般的に割り当てられた文字列のキャッシュを有効にします。
トム・ホーティン いくつかのベンチマークを改善するためのある種のキャッシュについて説明します。私がそれを考えたときの私の観察は、メモリフットプリント(完全なガベージコレクションの後)がそれを持っていないことをはるかに下ろしたということでした。それは文書化されたパラメーターではなく、実際にいくつかのベンチマークを最適化することについてのみである可能性があります。私の観察では、それが助けになったということですが、私はそれに基づいて重要なシステムを構築しませんでした。
注意すべき2つのこと:
- 使ってはいけません
new String("abc")
コンストラクター、文字通りを使用してください"abc"
. - 使用を学ぶ インターン() 文字列クラスのメソッド。特に文字列を連結する場合、または文字列/バイト配列/などを文字列に変換する場合。
intern()
プールされた文字列を常に返します。
同一の文字列が可能な値の固定セットから来ている場合、タイプセーフ列挙はここで望むものです。文字列数を減らすだけでなく、より強固なアプリケーションになります。あなたのアプリ全体は、この文字列にセマンティクスが付いていることを知るでしょう、おそらくいくつかの利便性の方法さえあります。
私のお気に入りの最適化は、常にコードを作成するために擁護できるものです より良い, 、より速いだけではありません。 10回のうち9回、文字列をコンクリートタイプに置き換えると、より正確で自己文書化されたコードが発生します。