Javaは、フードの下で弦のフライ級パターンをどのように実装していますか?

StackOverflow https://stackoverflow.com/questions/2909848

質問

文字列の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つのこと:

  1. 使ってはいけません new String("abc") コンストラクター、文字通りを使用してください "abc".
  2. 使用を学ぶ インターン() 文字列クラスのメソッド。特に文字列を連結する場合、または文字列/バイト配列/などを文字列に変換する場合。

intern() プールされた文字列を常に返します。

同一の文字列が可能な値の固定セットから来ている場合、タイプセーフ列挙はここで望むものです。文字列数を減らすだけでなく、より強固なアプリケーションになります。あなたのアプリ全体は、この文字列にセマンティクスが付いていることを知るでしょう、おそらくいくつかの利便性の方法さえあります。

私のお気に入りの最適化は、常にコードを作成するために擁護できるものです より良い, 、より速いだけではありません。 10回のうち9回、文字列をコンクリートタイプに置き換えると、より正確で自己文書化されたコードが発生します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top