ボックス形式のLong値127と128の比較


110

条件を使用して2つのLongオブジェクトの値を比較したいif。これらの値が128未満の場合if条件は適切に機能しますが、128以上の場合、比較は失敗します。

例:

Long num1 = 127;
Long num2 = 127;

if (num1 == num2) {
    // Works ok
}

上記のコードの比較は正しく機能しますが、以下のコードでは失敗します。

Long num1 = 128;
Long num2 = 128;

if (num1 == num2) {
    // Does NOT work
}

Long変数と127より大きい値の比較に問題があるのはなぜですか?変数のデータ型が長いプリミティブに変更された場合、比較はすべてのケースで機能します。

回答:


212

TL; DR

Javaはボックス化されたIntegerインスタンスをから-128にキャッシュし127ます。を使用==して値の代わりにオブジェクト参照を比較しているので、キャッシュされたオブジェクトのみが一致します。ボックス化されていないプリミティブ値を使用するか、オブジェクトを比較するために使用します。long.equals()Long

長い(しゃれた)バージョン

Long変数と127より大きい値の比較に問題があるのはなぜですか?上記の変数のデータ型がプリミティブ(ロング)の場合、コードはすべての値に対して機能します。

Javaは、-128〜127の範囲の整数オブジェクトインスタンスをキャッシュします。それは言った:

  • N Long変数に値127cached)を設定すると、同じオブジェクトインスタンスがすべての参照によってポイントされます。(N変数、1インスタンス)
  • N変数に値を設定すると128キャッシュされない)、すべての参照によってポイントされるオブジェクトインスタンスが作成されます。(N変数、Nインスタンス)

これが理由です:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2);

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4);

これを出力します:


以下のために127Lの値は、両方の参考文献(val1とVAL2)メモリ内の同じオブジェクト・インスタンスへのポイント(キャッシュ)するので、それは返しtrue

一方、128の値の場合、メモリにキャッシュされるインスタンスがないため、ボックス化された値の新しい割り当てに対して新しいインスタンスが作成され、2つの異なるインスタンス(val3とval4によってポイントされる)になりfalse、それらの間の比較。

これは、プリミティブ値ではなく2つのLong オブジェクト参照を演算子で比較しているためにのみ発生します。このキャッシュメカニズムがなければ、これらの比較は常に失敗するため、ここでの本当の問題は、ボックス化された値と演算子を比較することです。long====

これらの変数をプリミティブlong型に変更すると、これを防ぐLongことができますが、オブジェクトを使用してコードを維持する必要がある場合は、次の方法でこれらの比較を安全に行うことができます。

System.out.println(val3.equals(val4));                     // true
System.out.println(val3.longValue() == val4.longValue());  // true
System.out.println((long)val3 == (long)val4);              // true

(キャストの場合でも、適切なnullチェックが必要です)

IMO、オブジェクト比較を処理するときは常に.equals()メソッドを使用することをお勧めします。

参照リンク:


15

Javaは-128から127までのプリミティブ値をキャッシュします。2つのLongオブジェクトを比較する場合、javaは内部的にプリミティブ値に型キャストして比較します。しかし、127を超えると、Longオブジェクトはタイプカーストになりません。Javaは.valueOf()メソッドによって出力をキャッシュします。

このキャッシングは、バイト、ショート、ロングで-128から127の範囲で機能します。整数キャッシングでは、-128からjava.lang.Integer.IntegerCache.highまたは127のいずれか大きい方の範囲で機能します。 java.lang.Integer.IntegerCache.highを使用してキャッシュする必要があります。

 For example:
    If we set java.lang.Integer.IntegerCache.high=500;
    then values from -128 to 500 will get cached and 

    Integer a=498;
    Integer b=499;
    System.out.println(a==b)

    Output will be "true".

FloatおよびDoubleオブジェクトはキャッシュされません。

キャラクターは0から127までキャッシュを取得します

2つのオブジェクトを比較しています。したがって、==演算子はオブジェクト参照の等価性をチェックします。それには次の方法があります。

1)両方のオブジェクトをプリミティブ値に型キャストして比較します

    (long)val3 == (long)val4

2)オブジェクトの値を読み取り、比較する

    val3.longValue() == val4.longValue()

3)オブジェクト比較でequals()メソッドを使用します。

    val3.equals(val4);  

14

num1そしてnum2ロングオブジェクトです。equals()それらを比較するために使用する必要があります。 ==JVMボックスのプリミティブの方法が原因で比較が機能する場合がありますが、それに依存しません。

if (num1.equals(num1))
{
 //code
}

1
これ(より良い)、またはの戻り値を比較します.longValue()
Giulio Franco

4

Javaで非プリミティブ(別名オブジェクト)を==比較すると、値ではなく参照が比較されます。Longはクラスなので、Long値はオブジェクトです。

問題は、Java開発者が使用する人々を望んでいたということであるLong彼らは使用のようなlongことを本質的な特徴であるオートボクシングの概念につながった互換性、、、提供するために、long-valuesに変更されLong、必要に応じて-objectsおよびその逆を。ただし、完全に指定されていないため、オートボクシングの動作は常に正確に予測できるわけではありません。

したがって、安全で予測可能な結果を​​得るためには、常に.equals()オブジェクトの比較に使用し、この場合はオートボクシングに依存しません。

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.