多くのJava開発者が
String.intern()メソッドを知っているか、少なくとも聞いたことがあると
String.intern()ます。 しかし、誰もがアプリケーションでそれを使用したり、どの場合にそれが有用で、まったく有用であるかを想像しているわけではありません。 そのため、プロジェクトの1つでこの方法に出くわすまでは一緒でした。 その瞬間、私はその使用の意味と特徴を知りたいと思い、Yahoo!の主要な開発者による非常に興味深い記事に出会いました。 Ethan Nicholasの名前で、その翻訳を、Java言語に無関心でないHabrコミュニティのその部分と共有したいと思います。
伝聞だけでこの方法を知っている人は、猫の下で歓迎します。
文字列は現代のプログラミング言語の基本部分であり、数字と同じくらい重要です。 したがって、JavaプログラマーはJavaプログラマーについて堅実な考えを持っている必要があると想定できますが、残念なことに、これは常に当てはまるわけではありません。
今日、
Xerces (Javaに含まれるXMLパーサー)のソースコードを見て、私を驚かせた行に出会いました。
com.sun.org.apache.xerces.internal.impl.XMLScanner:395protected final static String fVersionSymbol = "version".intern();次に、これと定義された行がさらにいくつか見つかり、それぞれが
インターンになりました 。 では、
intern()とは何ですか? 間違いなくご存じのとおり、Javaでオブジェクトを比較するには2つの異なる方法があります。
==演算子を使用するか、
equals()メソッドを使用できます。
==演算子は、2つの参照が同じオブジェクトを参照しているかどうかを比較し、
equals()は、2つのオブジェクトに同じデータが含まれているかどうかを比較します。
Javaを学習するときに最初に学ぶことの1つは、2つの文字列を比較するために
==ではなく
equals()使用することです。 たとえば、
new String("Hello") == new String("Hello")と比較すると、これらはクラスの2つの異なるインスタンスであるため、結果は
falseです。
equals()を使用する
equals() 、期待どおり
trueになり
true 。 残念ながら、
equals()は文字ごとの文字列比較を実行するため、非常に遅くなる可能性があります。
なぜなら
==演算子はIDをチェックし、2つのポインターを比較するだけでよく、明らかにこれは
equals()よりもはるかに高速
equals() 。 したがって、同じ行を複数回比較する場合、文字比較の代わりにオブジェクトIDチェックを使用することで、パフォーマンスを大幅に向上させることができます。
主なアルゴリズム:
1)文字列のハッシュセットを作成する
2)扱っている文字列(文字のシーケンスとして)がすでにセットにあることを確認します
3)はいの場合、セットの文字列を使用します
4)それ以外の場合は、この文字列をセットに追加してから使用します
このアルゴリズムを使用すると、2つの文字列が同一の文字シーケンスである場合、クラスの1つのインスタンスであることが保証されます。 これは、
equals()代わりに
==を使用して文字列を安全に比較できることを意味しますが、繰り返しの比較よりもパフォーマンスが大幅に向上します。
幸いなことに、Javaにはすでにこのアルゴリズムの実装が含まれています。 これは、
java.lang.Stringクラスの
intern()メソッドです。 式
new String("Hello").intern() == new String("Hello").intern()は
true返し、
intern()を使用せずに
false返し
false 。
なぜ私は見るのに驚いたのですか
protected final static String fVersionSymbol = "version".intern();Xercesソースコードに? 明らかに、この行は複数の比較に使用されます。 彼女をインターンすることは理にかなっていますか?
もちろんそうです。 これが、Javaが
すでにこれを行う理由です。 クラスで発生するすべての定数文字列は自動的にインターンされます。 これには、独自の定数(上の
"version"行など)と、クラスファイル形式の一部である他の行(クラス名、メソッドシグネチャなど)の両方が含まれます。 これは式にも適用されます。
"Hel" + "lo" javacによって
"Hello"と同じ方法で処理されるため、
"Hel" + "lo" == "Hello"は
true返し
true 。
したがって、定義により、タイプ
"version"定数文字列で
intern()を呼び出した結果は、宣言したものとまったく同じオブジェクトになります。 つまり、
"version" == "version".intern()常にtrueです。 文字列が定数ではない場合、インターンをインターンする必要があり、他のインターンされた文字列とすばやく比較できるようにしたい。
また、文字列をインターンするとき、次のようにメモリ使用量の利点を得ることができます。 このシーケンスを何度参照しても、文字列内の一連の文字のインスタンスを1つだけ格納します。 これが、クラスファイルの文字列定数がインターンされる主な理由です。たとえば、
java.lang.Objectなど、参照するクラスの数を考え
java.lang.Object 。 クラス名
java.lang.Objectはこれらの各クラスに表示されますが、
intern()魔法のおかげで、メモリ内の1つのインスタンスにのみ表示されます。
結論は?
intern()は便利な方法であり、生活を楽にすることができますが、適切に使用するようにしてください。
翻訳者から(私が思ったように)理解しやすくするために、ソーステキストを数回歪ませたことをおaびします。
Habrasocietyに私を招待してくれたノーブル
habrayuzerに感謝します。
更新する他のソースから学んだ次の情報は、ここでは不必要ではないと思います。
1.文字列プールは、「Perm Gen」領域に保存されます。この領域は、非ユーザーJVMオブジェクト(クラスなど)用に予約されています。 これを無視すると、予想外にOutOfMemoryエラーが発生する場合があります。
2.抑留ラインは永久に保存されません。 参照されていない行もガベージコレクターによって削除されます。
3.ほとんどの場合、文字列比較がアプリケーションの主要な(または非常に頻繁な)操作であり、比較される文字列の長さが異なる場合を除き、intern()を使用してもパフォーマンスが大幅に向上することはありません。