jvmの文字列について話す

一定のプール

3つの一定のプール

  • クラスファイルの定数プール:定数プール
  • ランタイム定数プール:クラスファイル内の定数プールは、クラスローダーによって解析され、メソッド領域のInstanceKlassクラスの下のConstantPool * _constantsに格納されます。
  • 文字列定数プール:これは、ヒープの下のデータ構造文字列プールであり、基になるHashTable、キー値ストレージフォームによって実現されます。
    • 文字列の内容+長さでハッシュ値を生成します。ハッシュをキーに変換する
    • 値は、StringクラスのinstanceOopDescをHashtableEntryにカプセル化することです。

実験

  • String s1 = "11"; "11"
    によって生成されたStringオブジェクトは、HashtableEntryに直接カプセル化され、スタック内の変数はStringオブジェクトを指します。このキーが存在するかどうかを確認するためにHashTableに移動し、Stringオブジェクト参照を直接返します。ここに画像の説明を挿入
  • String s1 = new String( "11");
    新しい命令が呼び出されると、Striオブジェクトが生成されます。このとき、キーが存在するかどうかを確認するためにHashTableに移動します。存在する場合は、直接StringオブジェクトのChar配列。つまり、typeArrayOopDeseの新しいStringオブジェクトへの参照。
    ここに画像の説明を挿入
  • HashTableで検索するときに、見つかった場合は、Stringオブジェクトへの参照を直接返します。
    ここに画像の説明を挿入
  • 明らかに、newを使用する場合も同じですが、それでもStringオブジェクトインスタンスが作成されます。
    ここに画像の説明を挿入

スプライシングストリングの最下層を実現する方法

  • 二重引用符+二重引用符
public class TestString_5 {
    
    
    public static void main(String[] args) {
    
    
    	test2();
    }
    public static void test2() {
    
    
        String s1 = "1";
        String s2 = "1";
        String s = s1 + s2;
    }
}
  • バイトコード
0 ldc #2 <1>
 2 astore_0
 3 ldc #2 <1>
 5 astore_1
 6 new #3 <java/lang/StringBuilder>
 9 dup
10 invokespecial #4 <java/lang/StringBuilder.<init>>
13 aload_0
14 invokevirtual #5 <java/lang/StringBuilder.append>
17 aload_1
18 invokevirtual #5 <java/lang/StringBuilder.append>
21 invokevirtual #6 <java/lang/StringBuilder.toString>
24 astore_2
25 return

以上のことから、実際には以下のようなコードが使用されていることがわかります。

new StringBuilder().append("1").append("1").toString();
// StringBuilder的toString()调用的是:
new String(char[], 0, count);
//上面这种创建会直接生成String实例,并没有加入到常量池中去。
//可以通过intern()方法将其放入常量池。
  • 次のコードスペースの変更について説明します
String str ="1"+"2"+new String("3")+"4"+"5"+new String("6")+"7";
//上面看字节码等价于下面
String str ="12"+new String("3")+"45"+new String("6")+"7";

「12」、「3」、「45」、「6」、「7」の文字列インスタンスとChar []インスタンスをメモリに作成し、定数プールに配置しました。最後の「1234567」文字列インスタンスとChar [ ]インスタンスであり、定数プールに入れられません

intern()の概要

  • JDK1.6では、この文字列オブジェクトを文字列プールに入れてみてください。
    • 文字列プールにある場合、配置されません。既存の文字列プール内のオブジェクトのアドレスを返します
    • そうでない場合は、このオブジェクトのコピーを作成して文字列プールに入れ、文字列プール内のオブジェクトアドレスを返します。
  • JDK1.7以降、この文字列オブジェクトを文字列プールに入れてみてください。
    • 文字列プールにある場合、配置されません。既存の文字列プール内のオブジェクトのアドレスを返します
    • そうでない場合は、オブジェクトの参照アドレスをコピーして文字列プールに入れ、文字列プールに参照アドレスを返します。

おすすめ

転載: blog.csdn.net/null_zhouximin/article/details/112690610