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);
为什么输出结果是:
true
false
高洛峰2017-04-17 17:51:54
リーリー
Java メモリ モデルには文字列定数プールと呼ばれる領域があり、文字列定数を格納します。
まず、jdkのバージョンが1.6以下の場合、上記のコードを実行した結果は
となります。 リーリーjdk バージョンが 1.6 以降の場合、上記のコードの実行結果は
リーリー上記の 2 つの異なる結果の理由は、jvm が intern() メソッドを異なる方法で実装しているためです。
jdk1.6 以前では、intern() を呼び出します
定数プールに等しい値を持つ文字列がない場合、jvm は文字列を作成プールにコピーし、その文字列を定数プールに返します。
jdk1.7 以降では、intern() を呼び出します
定数プールに等しい値を持つ文字列がない場合、jvm は現在の文字列の参照を定数プールに記録し、現在の文字列の参照を返します。
次に、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
になります。
ringa_lee2017-04-17 17:51:54
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
です。