Javaの文字列メモリプールの実装はフライウェイトパターンに従いますか?
私がこの疑問を持っている理由は、インターンには外因性の状態が関与していないことがわかります。GoFで、私は内因性と外因性の状態の間に適切なバランスがあるべきだと読みました。しかし、インターンではすべてが本質的です。
あるいは、属性に関して厳密な規則はなく、オブジェクトを共有してメモリを削減するだけで、それをフライ級と呼ぶのに十分であると言えます。
私が理解するのを手伝ってください。
Javaの文字列メモリプールの実装はフライウェイトパターンに従いますか?
私がこの疑問を持っている理由は、インターンには外因性の状態が関与していないことがわかります。GoFで、私は内因性と外因性の状態の間に適切なバランスがあるべきだと読みました。しかし、インターンではすべてが本質的です。
あるいは、属性に関して厳密な規則はなく、オブジェクトを共有してメモリを削減するだけで、それをフライ級と呼ぶのに十分であると言えます。
私が理解するのを手伝ってください。
はい、String.intern()
実装はフライウェイトパターンに従います。
javadocが言うように
文字列オブジェクトの正規表現を返します。最初は空の文字列のプールは、Stringクラスによってプライベートに維持されます。
インターンメソッドが呼び出されたときに、equals(Object)メソッドによって決定されたこのStringオブジェクトに等しい文字列がプールにすでに含まれている場合、プールからの文字列が返されます。それ以外の場合、このStringオブジェクトはプールに追加され、このStringオブジェクトへの参照が返されます。
したがって、任意の2つの文字列sおよびtについて、s.equals(t)が真である場合に限り、s.intern()== t.intern()が真になります。
すべてのリテラル文字列と文字列値の定数式がインターンされます。文字列リテラルは、Java言語仕様の§3.10.5で定義されています
内部化された文字列は「PermGen」スペースにあり、返される文字列オブジェクトでは、等しい値に対して常に同じオブジェクトを返すため.intern()
、演算子を使用できます。==
.intern()
次に.intern()
、今日のJVMはプールをガベージできるため、メソッドはリークを生成しないことを覚えておいてください。
この記事も読んでみてください。
インターンに関係なく、Java Stringは、文字列と、同様のメソッド呼び出しchar[]
を介して文字列から派生した文字列との間で共有することにより、フライウェイトパターンを利用します。substring
ただし、これには裏返しがあります。巨大な文字列の小さなサブ文字列を取得すると、巨大な文字列はchar[]
ガベージコレクションの対象になりません。
注: OpenJDKバージョン1.7.0_06以降、上記は廃止されました。コードが変更されchar[]
、インスタンス間で共有されなくなりました。substring()
新しい配列を作成します。
他の人が述べたように、 String.intern() はすべてキャッシングに関するものです。プールに既に格納されている文字列リテラルへの参照を返します。このように、既存のオブジェクトを使用するため、flyweight パターンに似ていますが、メモリ消費が少なくなり、パフォーマンスが向上します (ただし、intern には、文字列プールでのルックアップの独自のパフォーマンス オーバーヘッドもあります)。したがって、この 2 つは似ているように見えますが、実際にはそうではありません。
Flyweight は、オブジェクトの immutables internals を共有することです。Interning は、オブジェクト全体をキャッシュするだけです。