Javaの文字列定数プール
Javaには2つの形式の文字列オブジェクト作成があります。 1つは、string str = "droid"などの文字通りの形式です。もう1つは、string str = new string( "droid");など、新しいものを使用してオブジェクトを構築する標準的な方法です。コードを作成するときに、特に文字通りの方法を作成するときに、これら2つの方法をよく使用します。ただし、これらの2つの実装は、実際にはパフォーマンスとメモリの使用に違いがあります。これはすべて、JVMが文字列定数プールまたはストリングリテラルプールである文字列オブジェクトの繰り返しの作成を減らすために特別なメモリを維持しているという事実によるものです。
それがどのように機能するか
文字列オブジェクトがコードのリテラル形式で作成されると、JVMは最初にリテラルを確認します。文字列定数プールに同じコンテンツを持つ文字列オブジェクトへの参照がある場合、参照が返されます。それ以外の場合、新しい文字列オブジェクトが作成され、参照が文字列定数プールに配置され、参照が返されます。
例を挙げてください
文字通りの作成フォーム
string str1 = "droid";
JVMはこのリテラルを検出します。ここでは、コンテンツを持つオブジェクトはドロイドが存在しないと考えています。 JVMは、文字列定数プールを介してドロイドコンテンツを含む文字列オブジェクトを見つけることができないため、この文字列オブジェクトを作成し、作成したばかりのオブジェクトの参照を文字列定数プールに配置し、可変STR1への参照を返します。
次にこのようなコードがある場合
string str2 = "droid";
同様に、JVMはこのリテラルを検出する必要があります。文字列定数プールを検索することにより、JVMはコンテンツが「ドロイド」文字列オブジェクトが存在することを発見したため、既存の文字列オブジェクトの参照を変数STR2に返します。ここでは、新しい文字列オブジェクトが再作成されないことに注意してください。
Str1とStr2が同じオブジェクトを指しているかどうかを確認すると、このコードを使用できます
System.out.println(str1 == str2);
結果は真です。
新しいで作成します
string str3 = new String( "Droid");
Stringオブジェクトを作成するために新しい使用を使用すると、String Constantプールに同じコンテンツを持つオブジェクトへの参照があるかどうかに関係なく、新しい文字列オブジェクトが作成されます。次のコードを使用してテストしましょう。
string str3 = new String( "Droid");
System.out.println(str1 == str3);
結果は私たちが考えるように偽りであり、2つの変数が異なるオブジェクトを指していることを示しています。
インターン
上記の新しいで作成された文字列オブジェクトの場合、文字列定数プールへの参照を追加する場合は、Internメソッドを使用できます。
インターンを呼び出した後、最初に文字列定数プールにオブジェクトへの参照があるかどうかを確認します。存在する場合は、この参照を変数に返します。そうしないと、参照が追加され、変数に返されます。
string str4 = str3.intern();
System.out.println(str4 == str1);
出力の結果は真です。
難しい問題
前提条件?
文字列定数プールを実装するための前提条件は、Javaの文字列オブジェクトが不変であり、複数の変数が同じオブジェクトを共有することを安全に保証できることです。 Javaの文字列オブジェクトが可変であり、1つの参照操作がオブジェクトの値を変更すると、他の変数も影響を受けます。明らかにこれは不合理です。
参照またはオブジェクト
この質問は、文字列定数プールが参照またはオブジェクトに保存されている場合に最も一般的です。文字列定数プールは、オブジェクトではなくオブジェクトの参照を保存します。 Javaでは、オブジェクトはヒープメモリに作成されます。
検証を更新すると、受け取った多くのコメントもこの問題について議論しており、私はそれを単純に検証します。環境を確認します
22:18:54-androidyue〜/videos $ cat/etc/os-releasename = fedoraversion = "17(beefy miracle)" id = fedoraversion_id = 17pretty_name = "fedora 17(beefy奇跡) "ANSI_COLOR =" 0; 34 "CPE_NAME =" CPE:/O:Fedoraproject:Fedora:17 "22:19:04-androidyue〜/videos $ java -versionjavaバージョン" 1.7.0_25 "openjdk runtime環境(Fedora-2.3.12.1.1.fc17 64ビットサーバーVM(ビルド23.7-B01、混合モード)
確認のアイデア:次のJavaプログラムは、82mサイズのビデオファイルを読み取り、文字列の形でインターン操作を実行します。
22:01:17 -androidyue〜/videos $ ll -lh | grep why_to_learn.mp4-rw-rw-r--。 1 Androidyue androidyue 82m 2013年10月20日why_to_learn.mp4
検証コード
Import java.io.bufferedReader; Import java.io.fileNotFoundException; Import java.io.filereader; Import java.io.io.ioexception; public class testmain {private static string filecontent; public static void main(string [] args){filecontent = readfiletostring(args [0]); if(null!= filecontent){filecontent = filecontent.intern(); System.out.println( "Not Null"); }} private static string readfiletostring(string file){bufferedreader reader = null; try {reader = new BufferedReader(new FileReader(file)); stringbuffer buff = new StringBuffer();文字列線; while((line = reader.readline())!= null){buff.append(line); } return buff.toString(); } catch(filenotfoundexception e){e.printstacktrace(); } catch(ioexception e){e.printstacktrace(); }最後に{if(null!= reader){try {reader.close(); } catch(ioexception e){e.printstacktrace(); }}} nullを返します。 }}弦の定数プールはヒープメモリの永続的な発電に存在するため、Java 8の前に適しています。文字列オブジェクトが文字列定数プールに存在する場合、java.lang.outofmemoryerror permgenスペースエラーをスローする必要があります。
Java -xx:permsize = 6m testmain〜/videos/why_to_learn.mp4
プルーフプログラムを実行してもOOMはスローされませんが、これはオブジェクトまたは参照として保存されていることを証明することはできません。
しかし、これは少なくとも、文字列の実際のコンテンツオブジェクトchar []が文字列定数プールに保存されていないことを証明しています。この場合、文字列の定数プールが文字列オブジェクトまたは文字列オブジェクトを参照することはそれほど重要ではありません。しかし、個人はまだ参照を保存する傾向があります。
長所と短所
文字列の定数プーリングの利点は、同じコンテンツの文字列の作成を減らし、メモリスペースを節約することです。
欠点を言わなければならない場合は、CPUコンピューティング時間を犠牲にしてスペースを交換することです。 CPU計算時間は、主に文字列定数プールに同じコンテンツを持つオブジェクトへの参照があるかどうかを見つけるために使用されます。ただし、内部実装はハッシュテーブルであるため、計算コストは低くなります。
GCリサイクル?
文字列定数プールは共有文字列オブジェクトへの参照を保持しているため、これらのオブジェクトをリサイクルできないことを意味しますか?
まず、質問の共有オブジェクトは一般に小さくなります。私が確認した限り、以前のバージョンでは実際にそのような問題がありましたが、参照が弱いため、この問題は現在消えてはなりません。
この問題については、この記事について詳しく知ることができます。インターン文字列:Java Glossary
インターンを使用しますか?
インターンを使用するための前提条件は、あなたが本当にそれを使用する必要があることを知っていることです。たとえば、ここには数百万の記録があり、レコードの特定の価値はカリフォルニア州、米国で何度もあります。このような文字列オブジェクトを何百万も作成したくありません。インターンを使用して、メモリに1つのコピーのみを保持できます。インターンの詳細な理解については、文字列#インターンの詳細な分析を参照してください。
常に例外はありますか?
次のコードがいくつかの文字列オブジェクトを作成し、文字列定数プールにいくつかの参照を保存することをご存知ですか?
文字列テスト= "a" + "b" + "c";
答えは、1つのオブジェクトのみが作成され、一定のプールに1つの参照のみが保存されるということです。 Javapの逆コンパイルを使用して、それを見てみましょう。
17:02 $ javap -c testinternedpoolgccccccccccccccccccccccccccccccc.java "public class testinternedpoolgcはjava.lang.object {public testinternedpoolgc();コード:0:ALOAD_0 1:Invokespecial#1; // Method Java/Lang/Object。 "<init>" :()v 4:ReturnPublic Static void Main(java.lang.String [])throws Java.lang.exception;コード:0:LDC#2; //文字列ABC 2:store_1 3:return見たことがありますか?実際、編集期間中、これらの3つのリテラルは1つに合成されています。これは実際には、冗長な文字列オブジェクトの作成を回避し、文字列縫製の問題を抱えていない最適化です。文字列ステッチについては、Javaの詳細を表示できます:文字列ステッチ。
上記は、Javaの文字列定数プールに関する情報の編集です。今後も関連情報を追加し続けます。このサイトへのご支援ありがとうございます!