Java:整数の等しいと==


152

Java 1.5以降、多くの状況でIntegerとほとんど交換できますint

ただし、コードに潜在的な欠陥があり、少し驚いた。

次のコード:

Integer cdiCt = ...;
Integer cdsCt = ...;
...
if (cdiCt != null && cdsCt != null && cdiCt != cdsCt)
    mismatch = true;

値が等しい場合、不一致を誤って設定しているように見えましたが、どのような状況下であるかはわかりません。私はEclipseにブレークポイントを設定し、Integer値が両方とも137であることを確認しました。ブール式を検査したところ、falseであることがわかりましたが、ステップオーバーすると、ミスマッチをtrueに設定していました。

条件を次のように変更します。

if (cdiCt != null && cdsCt != null && !cdiCt.equals(cdsCt))

問題を修正しました。

なぜこれが起こったのかについて誰かが光を当てることができますか?これまでのところ、自分のPCのローカルホストでの動作のみを確認しました。この特定のケースでは、コードは約20回の比較に成功しましたが、2回失敗しました。問題は一貫して再現可能でした。

それが一般的な問題である場合は、他の環境(開発とテスト)でエラーを引き起こしているはずですが、これまでのところ、このコードスニペットを実行する何百ものテストの後に問題を報告した人はいません。

==2つのInteger値を比較するために使用することはまだ正当ではありませんか?

以下のすべての良い答えに加えて、次のスタックオーバーフローリンクにはかなりの追加情報があります。実際には元の質問に答えていたはずですが、質問でオートボクシングについて言及しなかったため、選択した提案には表示されませんでした。

コンパイラ/ JVMがオートボクシングを「機能するだけ」にできないのはなぜですか?

回答:


238

JVMは整数値をキャッシュしています。==は-128から127までの数値でのみ機能します http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


1
ありがとう、それは確かに137が失敗する理由を説明しています!そして、それがなぜ一般的な問題ではないのかという私の質問にも答えます。これから遭遇することになる95%のケースでは、値は127未満になります。今のところ5%の場合はそうではありませんが、これで問題ありません。
ジェレミーグッデル

1
興味深い副注:2週間前までは、cdiCtとcdsCtはどちらもintだったので問題ありませんでしたが、異なる方法で処理されるnullの状況をチェックするために、整数にする必要がありました...
Jeremy Goodell

3
@ジェレミーうん、それはかなりあいまいな問題ですが、原則として、オブジェクトには.equals()を使用し、プリミティブには==を使用します。等価テストを自動アンボックス化に依存することはできません。
Adam

1
笑、チェックマークを返して!とにかく、コリンはすでに十分以上のポイントを持っているように見えます。
Jeremy Goodell、2010

2
new Integer(1)!= new Integer(1)にも注意してください。new ALWAYSは新しいアドレスを返します。オートボクシングはキャッシュバージョンを使用します。整数を返す(それらを更新せずに)他の方法は、おそらくキャッシュされた値も返します。
ビルK

77

2つのオブジェクトをInteger単純な==オブジェクトと比較することはできないため、ほとんどの場合、参照は同じではありません。

トリックがあり、Integer-128から127の間で、参照はInteger.valueOf()小さな整数をキャッシュするオートボクシングが使用するのと同じになります。

ボックス化される値pがtrue、false、バイト、\ u0000から\ u007fの範囲の文字、または-128から127までの整数または短い数値の場合、r1とr2を2つのボックス化変換の結果とするの 常にr1 == r2です。


リソース:

同じトピックについて:


1
JLSからの保証ですか、それともOracle JVMに対する保証ですか?
するThorbjörnRavnアンデルセン

引用部分はJLSからのものであるため、JLSからの保証です
Colin Hebert 2012

Re:保証します。それでもあまり頼りません。 new Integer(1) == new Integer(1)まだ偽です。
Thilo、2015

@Thilo new ... == new ...は常にfalseです。
MC皇帝

2
@Thilo True、equals()オブジェクトを扱うときに常に使用します。これは、Javaを学ぶときに最初に知っておくべきことの1つです。ちなみに、私はのコンストラクターIntegerがプライベートであること、つまりインスタンスが常にvalueOf()メソッドを通じて作成されていることを推測しました。しかし、コンストラクターはパブリックであることがわかります。
MC皇帝

5

問題は、2つのIntegerオブジェクトがまさにそのオブジェクトであるということです。2つのオブジェクト参照を比較しているのであり、その中の値ではないため、これらは一致しません。.equalsオブジェクト参照比較とは対照的に、値比較を提供するために明らかにオーバーライドされます。


良い答えが、それは唯一の137のために失敗している理由、それは説明していない
ジェレミーグッデル

4

Integer参照を参照します。つまり、値ではなく、同じオブジェクトを指している場合に比較している参照を比較します。したがって、あなたが見ている問題。プレーンintタイプで非常にうまく機能する理由は、に含まれる値のボックス化を解除するためIntegerです。

もしあなたがあなたがしていることをしているなら、なぜif声明が最初からあるのかを付け加えてもいいですか?

mismatch = ( cdiCt != null && cdsCt != null && !cdiCt.equals( cdsCt ) );

4

"=="は常に、値のメモリロケーションまたはオブジェクト参照を比較します。equalsメソッドは常に値を比較します。ただし、equalsは間接的に「==」演算子を使用して値を比較します。

整数は、整数キャッシュを使用して-128から+127までの値を格納します。==演算子を使用して-128から127までの値をチェックすると、trueが返されます。これらの値以外の場合はfalseを返します。

追加情報についてはリンクを参照してください


0

これらの与えられた素晴らしい答えに加えて、私が学んだことは、

参照で比較するつもりでない限り、オブジェクトを==で比較しないでください。


0

同様に、使用の正確さのために、比較を行う前に、次のように==、比較されたInteger値の1つをボックス解除することができます==

if ( firstInteger.intValue() == secondInteger ) {..

2番目は自動的に開梱されます(もちろん、null最初にを確認する必要があります)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.