String str1 = new StringBuilder("a").append("b").toString(); System.out.println(str1.intern() == str1); String str2 = new StringBuilder("c").toString(); System.out.println(str2.intern() == str2);
为什么输出结果是:truefalse
光阴似箭催人老,日月如移越少年。
リーリー
Java メモリ モデルには文字列定数プールと呼ばれる領域があり、文字列定数を格納します。
まず、jdkのバージョンが1.6以下の場合、上記のコードを実行した結果は
jdk バージョンが 1.6 以降の場合、上記のコードの実行結果は
上記の 2 つの異なる結果の理由は、jvm が intern() メソッドを異なる方法で実装しているためです。
jdk1.6 以前では、intern() を呼び出します
定数プールに等しい値を持つ文字列がない場合、jvm は文字列を作成プールにコピーし、その文字列を定数プールに返します。
jdk1.7 以降では、intern() を呼び出します
定数プールに等しい値を持つ文字列がない場合、jvm は現在の文字列の参照を定数プールに記録し、現在の文字列の参照を返します。
次に、jdk1.7 以降で上記のコードが true と false を取得する理由を説明します。
true
false
上記のコードを含むクラスが JVM によってロードされると、定数プールがあるため、a が実行されると、リテラル定数 b、c、str1.intern() が文字列定数プールにロードされます。文字列 ab が存在しない場合、JVM は定数プールに str1 の参照を記録し、str1 の参照を返します。そのため、コードの 2 行目の出力は true になります。
a
b
c
str1.intern()
ab
str1
str2 は、リテラル定数 c を使用して新しい文字列を構築します。この文字列の参照は、c が呼び出されるときの定数プール内のリテラル str2.intern() 文字列の参照とは異なります。プール c は既に JVM に存在しており、JVM は再構築された str2 とは異なる定数プール内の参照を直接返します。そのため、行 4 の出力は false になります。
str2
str2.intern()
intern() メソッドを呼び出す String オブジェクトは、まず定数プールからオブジェクトの equals 定数を見つけて返します。見つからない場合は、オブジェクトの equals 定数を定数プールに追加します。定数の適用を返します。 System.out.println(str1.intern() == str1); の出力は true です。これは、str1 が append 操作の後に定数プール内の定数への参照になるためです。 System.out.println(str2.intern() == str2); は、str2 が変数への参照であり、定数プールにないため、false として出力されます。 したがって、主に str.intern() == str が定数プール内の定数であるかどうかに基づいて、false が true であるか str であるかを判断する必要があります。そうである場合、結果は true になります。まさにfalseです。
intern()
equals
System.out.println(str1.intern() == str1);
append
System.out.println(str2.intern() == str2);
str.intern() == str
str
リーリー
Java メモリ モデルには文字列定数プールと呼ばれる領域があり、文字列定数を格納します。
まず、jdkのバージョンが1.6以下の場合、上記のコードを実行した結果は
となります。 リーリーjdk バージョンが 1.6 以降の場合、上記のコードの実行結果は
リーリー上記の 2 つの異なる結果の理由は、jvm が intern() メソッドを異なる方法で実装しているためです。
jdk1.6 以前では、intern() を呼び出します
jdk1.7 以降では、intern() を呼び出します
次に、jdk1.7 以降で上記のコードが
true
とfalse
を取得する理由を説明します。上記のコードを含むクラスが JVM によってロードされると、定数プールがあるため、
a
が実行されると、リテラル定数b
、c
、str1.intern()
が文字列定数プールにロードされます。文字列ab
が存在しない場合、JVM は定数プールにstr1
の参照を記録し、str1
の参照を返します。そのため、コードの 2 行目の出力はtrue
になります。str2
は、リテラル定数c
を使用して新しい文字列を構築します。この文字列の参照は、c
が呼び出されるときの定数プール内のリテラルstr2.intern()
文字列の参照とは異なります。プールc
は既に JVM に存在しており、JVM は再構築されたstr2
とは異なる定数プール内の参照を直接返します。そのため、行 4 の出力はfalse
になります。intern()
メソッドを呼び出す String オブジェクトは、まず定数プールからオブジェクトのequals
定数を見つけて返します。見つからない場合は、オブジェクトのequals
定数を定数プールに追加します。定数の適用を返します。System.out.println(str1.intern() == str1);
の出力はtrue
です。これは、str1
がappend
操作の後に定数プール内の定数への参照になるためです。System.out.println(str2.intern() == str2);
は、str2 が変数への参照であり、定数プールにないため、false
として出力されます。したがって、主に
str.intern() == str
が定数プール内の定数であるかどうかに基づいて、false
がtrue
であるかstr
であるかを判断する必要があります。そうである場合、結果はtrue
になります。まさにfalse
です。