Java の == での一貫性のない動作
質問
次のコードを考えてみましょう。
class test {
public static void main(String[] args) {
test inst_test = new test();
int i1 = 2000;
int i2 = 2000;
int i3 = 2;
int i4 = 2;
Integer Ithree = new Integer(2); // 1
Integer Ifour = new Integer(2); // 2
System.out.println( Ithree == Ifour );
inst_test.method( i3 , i4 );
inst_test.method( i1 , i2 );
}
public void method( Integer i , Integer eye ) {
System.out.println(i == eye );
}
}
出力されます:
false
true
false
最初は分かりました false
, == 演算子は、2 つの参照が同じオブジェクト上で機能しているかどうかのみをチェックしますが、この場合はそうではありません。
次の true
そして false
頭を悩ませてください。Java が考慮する理由 i3
そして i4
等しいけど i1
そして i2
違う?両方とも Integer にラップされていますが、ラップされてはいけません 両方 falseと評価されますか?この矛盾には実際的な理由があるのでしょうか?
解決
オブジェクトへのプリミティブのオートボックス化 (呼び出しで使用されるように) method
小さな値のキャッシュを使用します。から Java 言語仕様セクション 5.1.7:
ボックス化される値 p が true の場合、 false、バイト、範囲内の char \u0000 から \u007f、または int または short -128 から 127 までの数値を指定すると、 r1 と r2 は、任意の 2 つの結果です。 p のボックス変換。常に r1 == r2の場合。
その直後の仕様のディスカッション部分も興味深いです。特にJVMはキャッシュできる もっと 必要に応じて値を変更します。次のことを実行した結果を確信することはできません。
Integer i1 = 129;
Integer i2 = 129;
boolean b = (i1 == i2);
他のヒント
オートボックス化すると、-128 から 127 までの整数がキャッシュされ、同じラッパー オブジェクトが返されます。\u0000 から \u007F までのブール値と char 値も同様です
ほとんどの場合これが得られますが、JVM の実装によって異なります。
これは、ボックス化により、特定の値 (128 だと思います) 未満の整数が事前に構築されたオブジェクトを参照し、それ以上の値が新しいオブジェクトを参照するためです。
オートボクシングの用途 整数.値(i), new Integer(i) ではなく、Integer クラスのオブジェクトを構築します。
他の人が言ったように、valueOf() は主にスペース効率のためにキャッシュを使用します。
参照型では == を使用しないでください。これはほとんどの場合間違いです。
整数クラスには、頻繁に使用されるいくつかのインスタンスのキャッシュが含まれています。値の範囲は一般に JVM ごとに異なります (設定可能な場合もあります) が、一般に関連するコードは次のようなものになります。
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
(Sun JDK 1.6 のコード)
これはメモリを節約し、参照を使用して同等性をテストできるため、文字列インターニングに似ています (例: == 代わりに 等しい)
ラッピングは整数オブジェクトの数を最小限に抑えようとしており、メモリを節約するために 2 を表すオブジェクトを 1 つだけ作成しているのではないかと思います。
何が起こるかわからないオブジェクトに対して == を決して使用しないように注意してください。
オートボックス化では、いくつかのキャッシュ メカニズムが使用されます。通常は絶対に頼るべきではありません ==
, 、常に使用します equals
平等性を確認するため。