blog

JVMの文字列とインターン・メソッドから

学習JVMのプロセスは、文字列のインターン()メソッドに遭遇し、その後、非常に体系的ではないことを発見したインターネット上で多くを探したステートメントの多くは矛盾しています。だから私はこのレコードを勉...

Apr 20, 2020 · 6 min. read
シェア

序文

学習JVMのプロセスは、文字列のインターン()メソッドに遭遇し、その後、非常に体系的ではないことがわかったインターネット上でたくさん探して、文の多くは矛盾しています。だから私はこのレコードを勉強することにしました。

まず、intern()の意味を見てみましょう。

当面は、文字列定数プールに入れるだけです。

実践的進化

  • JDK1.7:このメソッドを呼び出すと、まず文字列定数プールに移動して既に存在するかどうかを確認し、既に存在する場合は、文字列定数プール内のこの定数のアドレス値を直接返します。
  • JDK1.7以降:このメソッドを呼び出すと、まず文字列定数プールに移動して既に存在するかどうかを確認し、既に存在する場合は、文字列定数プール内のこの定数のアドレス値を直接返し、存在しない場合は、文字列定数プール内のヒープに参照のコピーを保存し、そのアドレス値を返します。リテラルやnew String()で文字列を作成すると、定数プールはオブジェクトとして保存され、intern()メソッドでは、定数プールは参照として保存されます。以下はJDK7以降のバージョンで分析されたものです。

文字列を作成するいくつかの方法

  • String str= "abc": リテラルで。まず、同じ文字列が定数プールに既に存在するかどうかを確認します。存在する場合は、定数プールにその文字列への参照を返します。存在しない場合は、定数プールに文字列オブジェクトを作成し、その参照を返します。
  • String str = new String("abc")文字列オブジェクトを明示的に作成します。まずヒープにオブジェクトを作成し、同じ文字列が定数プールに既に存在するかどうかを確認し、存在する場合はヒープへの参照を直接返します。存在しない場合は、定数プールに文字列オブジェクトを作成し、ヒープへの参照を返します。
  • String str = "abc" + "de"定数スプライシング。String str = "abcde "と同等に最適化されてコンパイルされます。
  • String str = new String("abc") + new String("de")まず最初に、appendメソッドでStringBuilderオブジェクトを作成し、次にtoStringでStringに変換します。下は、appendメソッドでStringBuilderオブジェクトを作成し、最後にtoStringでStringに変換します。合計5つのオブジェクトが作成されます:ヒープ、文字列定数プール。これは、ループ本体でどの形式の文字列スプライシングが使用されても、多くのオブジェクトが生成され、メモリを浪費し、パフォーマンスに影響することを示しています。

intern()によって影響を受けるメモリ構造の完全な分析と4つの例

  • eg1
 @Test
 public void function1() {
 String str1 = new String("abc");
 String str2 = "abc";
 String intern = str1.intern();
 System.out.println(str1==str2);//false
 System.out.println("str1: "+System.identityHashCode(str1));//
 System.out.println("str2: "+System.identityHashCode(str2));//
 System.out.println("intern: "+System.identityHashCode(intern));//
 }

String str1 = new String("abc")ヒープと定数プールにオブジェクトを作成し、str1はヒープを指します。

文字列str2 = "abc" 定数プールで "abc "の参照を見つけ、定数プールの参照を直接返します。

String intern = str1.intern()定数プールで "abc "の参照を見つけたので、定数プールの参照を直接返します。

  • eg2
 @Test
 public void function2() {
 String str1 = new String("abc");
 String intern = str1.intern();
 String str2 = "abc";
 System.out.println(str1==str2);//false
 System.out.println("str1: "+System.identityHashCode(str1));//
 System.out.println("str2: "+System.identityHashCode(str2));//
 System.out.println("intern: "+System.identityHashCode(intern));//
 }

ここでは2行目と3行目の順番が変わっただけで、構造はeg1と全く同じです。

  • eg3
 @Test
 public void function3() {
// String hel = new String("hel");
// String lo = new String("lo");
// String str1 = hel+lo;
 String str1 = new String("hel") + new String("lo");
 String intern = str1.intern();
 String str2 = "hello";
 System.out.println(str1 == str2);//true
 System.out.println("str1: " + System.identityHashCode(str1));//
 System.out.println("str2: " + System.identityHashCode(str2));//
 System.out.println("intern: " + System.identityHashCode(intern));//
// System.out.println(System.identityHashCode(hel));//
// System.out.println(System.identityHashCode(hel.intern()));//
// System.out.println(System.identityHashCode(lo));//
// System.out.println(System.identityHashCode(lo.intern()));//
 }

String str1 = new String("hel") + new String("lo");コメントを解放すると、オブジェクトのメモリアドレスの詳細なハッシュコードが表示されます。ヒープ、文字列定数プールに:5つのオブジェクトの合計を作成します。

String intern = str1.intern();定数プールでは "hello "の参照を見つけられなかったので、定数プールでhelloオブジェクトの参照のコピーを保存し、参照アドレスを返します。

文字列str2 = "hello";定数プールでは "abc "参照で見つかったので、直接参照の定数プールに戻ります。str1はヒープへの参照を指し、internとstr2はヒープへのstr1の参照のコピーを指すので、これらは等しいです。

  • eg4
 @Test
 public void function4() {
// String hel = new String("hel");
// String lo = new String("lo");
// String str1 = hel+lo;
 String str1 = new String("hel") + new String("lo");
 String str2 = "hello";
 String intern = str1.intern();
 System.out.println(str1 == str2);//true
 System.out.println("str1: " + System.identityHashCode(str1));//
 System.out.println("str2: " + System.identityHashCode(str2));//
 System.out.println("intern: " + System.identityHashCode(intern));//
// System.out.println(System.identityHashCode(hel));//
// System.out.println(System.identityHashCode(hel.intern()));//
// System.out.println(System.identityHashCode(lo));//
// System.out.println(System.identityHashCode(lo.intern()));//
 }

String str1 = new String("hel") + new String("lo");str1はヒープを指しています。

文字列str2 = "hello";定数プール内の "abc "への参照が見つからなかったので、オブジェクトを作成し、定数プールへの参照を返します。

String intern = str1.intern();定数プールで "hello "の参照を見つけたので、直接参照アドレスを返します。str1はヒープへの参照を指し、インターンとstr2は定数プール内のstr1への参照を指すので、str1とstr2は等しくありません。

JDKでStringに加えられた変更

つの質問

文字列定数プールとインターン・メソッドの終わりを見れば、一定の理解が得られるはずです。しかし、ここでまだ2つの問題があります:

1.eg3の例では、文字列が "java"、"12"、"1122 "や他の特殊な文字列の例は保持されません。推測:定数プールがこれらの文字列に既に存在する場合、jvmの初期化。

2.単一のテストと同じコードを実行するメインスレッドを通して、結果は同じではありません。チェックした後、どのような魔法の値?

 public static void main(String[] args) {
 String s3 = new String("1") + new String("1");
 s3.intern();
 String s4 = "11";
 System.out.println(s3 == s4);//true
 }
 @Test
 public void fun4() {
 String s3 = new String("1") + new String("1");
 s3.intern();
 String s4 = "11";
 System.out.println(s3 == s4);//false
 }

この時点で本当に理解できないし、そのやり取りを共有したいと思っているので、興味があれば調べてみてください。

Read next

cssカスケードルール

1, カスケード・コンテキスト: 要素がカスケード・コンテキストを含んでいる場合、それはz軸において優れていると解釈することができます。 2, cascading level: 同じカスケード・コンテキストの要素がz軸上に表示される順序を決定します。 ここには興味深い問題があります。つまり、インリン...

Apr 20, 2020 · 5 min read