この記事では、Java の文字列定数プールについて詳しく説明します。必要な方は参考にしていただければ幸いです。
Java 設計者は、最も基本的な参照データ型として、String のパフォーマンスを向上させるために文字列定数プールを提供します。では、文字列定数プールの具体的な原理は何でしょうか。次の 3 つの質問があります。文字列定数プールを理解するには:
文字列定数プールの設計意図は何ですか?
文字列定数プールはどこですか?
文字列定数プールを操作するにはどうすればよいですか?
文字列定数プールの設計上の考え方
a. 文字列の割り当ては、他のオブジェクトの割り当てと同様に時間がかかります。最も基本的なデータ型として、大量の文字列を頻繁に作成するため、スペースのコストがかかり、プログラムのパフォーマンスに大きな影響を与えます。
b. パフォーマンスを向上させ、メモリのオーバーヘッドを削減するために、JVM は文字列定数をインスタンス化するときにいくつかの最適化を行いました。
キャッシュ領域と同様に、文字列の文字列定数プールを開きます。
文字列定数を作成するときは、まず文字列が文字列定数プールに存在するかどうかを確認します。
文字列が存在する場合は、参照インスタンスを返します。存在しない場合は、文字列をインスタンス化してプールに入れます。
c. 実装の基礎
この最適化を実現するための基礎は、文字列が不変であり、データの競合を気にせずに共有できることです。
ランタイム インスタンスによって作成されたグローバル文字列定数プールにはテーブルがあり、プール内の一意の各文字列オブジェクトの参照が常に維持されます。つまり、常に文字列定数プールを参照します。したがって、定数プール内のこれらの文字列はガベージ コレクターによってリサイクルされません。
コード: 文字列定数プールから対応する文字列を取得
String str1 = “hello”; String str2 = “hello”; System.out.printl("str1 == str2" : str1 == str2 ) //true
文字列定数プールはどこですか
解析時文字列定数プールの場所、まずヒープ、スタック、およびメソッド領域を理解します:
Heap
storedオブジェクトであり、各オブジェクトには対応するクラスが含まれます。
JVM には、すべてのスレッドで共有されるヒープ領域 (ヒープ) が 1 つだけあり、基本型とオブジェクト参照はヒープに格納されず、オブジェクト自体のみが格納されます。
オブジェクトはガベージ コレクターによってリサイクルされるため、サイズとライフ サイクルを決定する必要はありませんスタック
各スレッドにはスタック領域が含まれます。スタックにはスタック領域が 1 つだけあります 基本データ型のオブジェクトとカスタム オブジェクトへの参照 (オブジェクトではありません) を保存します#各スタック内のデータ (元の型とオブジェクト参照) はプライベートです
スタックは基本型変数領域、実行環境コンテキスト、演算命令領域(ストレージ演算命令)の3つに分かれています。
データへの参照がない場合、データサイズとライフサイクルがわかります。 、データは自動的に消えます
メソッド領域ヒープなどの静的領域はすべてのスレッドで共有されます
メソッド領域には次のものが含まれますプログラム全体で常に一意であるクラス、静的変数などの要素
メソッド領域に文字列定数プールが存在しますコード: スタック メソッド領域には、 strings
String str1 = “abc”; String str2 = “abc”; String str3 = “abc”; String str4 = new String(“abc”); String str5 = new String(“abc”);
インタビューの質問: String str4 = new String("abc) によって作成されるオブジェクトの数")?
1. 定数プールに "abc" オブジェクトがあるかどうかを確認します。
存在する場合は、対応する参照インスタンスを返します。
存在しない場合は、対応するインスタンス オブジェクトを作成します。
2. ヒープに新しい String("abc") オブジェクトを作成します
3. オブジェクトのアドレスを str4 に割り当て、参照を作成します
したがって、定数プール内の "abc" リテラル 次に、2 つのオブジェクトを作成します。それ以外の場合は、オブジェクトを作成し、参照を作成します。
リテラルに基づいて、このようなさまざまな質問がよくあります。
String str1 = new String("A" " B") ; オブジェクトはいくつ作成されますか?
String str2 = new String("ABC") "ABC" ; オブジェクトはいくつ作成されますか? #str1:
文字列定数 プール: "A"、"B"、"AB": 3ヒープ: new String("AB"): 1
参照: str1: 1 合計: 5
str2:
文字列定数プール: "ABC": 1
ヒープ: 新しい String("ABC"): 1
合計: 3
コード: 基本型の変数と定数、変数と参照はスタックに保存され、定数は定数プールに保存されます
#
int a1 = 1; int a2 = 1; int a3 = 1; public static int INT1 =1 ; public static int INT2 =1 ; public static int INT3 =1 ;
文字列定数プールの操作方法
JVM が文字列定数プールをインスタンス化する場合 String str1 = “hello”;
String str2 = “hello”;
System.out.printl("str1 == str2" : str1 == str2 ) //true
通过new操作符创建的字符串对象不指向字符串池中的任何对象,但是可以通过使用字符串的intern()方法来指向其中的某一个。java.lang.String.intern()返回一个保留池字符串,就是一个在全局字符串池中有了一个入口。如果以前没有在全局字符串池中,那么它就会被添加到里面
// Create three strings in three different ways. String s1 = "Hello"; String s2 = new StringBuffer("He").append("llo").toString(); String s3 = s2.intern(); // Determine which strings are equivalent using the == // operator System.out.println("s1 == s2? " + (s1 == s2)); // false System.out.println("s1 == s3? " + (s1 == s3)); // true
字面量和常量池初探
字符串对象内部是用字符数组存储的,那么看下面的例子:
String m = "hello,world"; String n = "hello,world"; String u = new String(m); String v = new String("hello,world");
1.会分配一个11长度的char数组,并在常量池分配一个由这个char数组组成的字符串,然后由m去引用这个字符串
2.用n去引用常量池里边的字符串,所以和n引用的是同一个对象
3.生成一个新的字符串,但内部的字符数组引用着m内部的字符数组
4.同样会生成一个新的字符串,但内部的字符数组引用常量池里边的字符串内部的字符数组,意思是和u是同样的字符数组
使用图来表示的话,情况就大概是这样的(使用虚线只是表示两者其实没什么特别的关系):
测试demo:
String m = "hello,world"; String n = "hello,world"; String u = new String(m); String v = new String("hello,world"); System.out.println(m == n); //true System.out.println(m == u); //false System.out.println(m == v); //false System.out.println(u == v); //false
结论:
m和n是同一个对象
m,u,v都是不同的对象
m,u,v,n但都使用了同样的字符数组,并且用equal判断的话也会返回true
以上がJavaの文字列定数プールの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。