282

ボックス化されたプリミティブ整数を次のような定数と比較すると、次のことがわかります。

Integer a = 4;
if (a < 5)

a自動的に開封され、比較が機能します。

しかし、ボックス化された 2 つのものIntegersを比較していて、等しいか小さいか大きいかを比較したい場合はどうなるでしょうか。

Integer a = 4;
Integer b = 5;

if (a == b)

上記のコードは、それらが同じオブジェクトであるかどうかを確認する結果になりますか、それともその場合は自動アンボックスになりますか?

どうですか:

Integer a = 4;
Integer b = 5;

if (a < b)

?

4

10 に答える 10

378

いいえ、== Integer、Long などの間で参照の等価性がチェックされます- つまり

Integer x = ...;
Integer y = ...;

System.out.println(x == y);

これは、等しいオブジェクトではなく、同じオブジェクトxy参照しているかどうかをチェックします。

そう

Integer x = new Integer(10);
Integer y = new Integer(10);

System.out.println(x == y);

印刷が保証されていますfalse。「小さい」自動ボックス化された値のインターンは、トリッキーな結果につながる可能性があります。

Integer x = 10;
Integer y = 10;

System.out.println(x == y);

これはtrue、ボクシングのルール ( JLS セクション 5.1.7 ) により、 を出力します。それはまだ使用されている参照の等価性ですが、参照本当に等しいです。

ボックス化される値 p が -128 から 127 までの int 型の整数リテラル (§3.10.1)、またはブール型リテラル true または false (§3.10.3)、または '\u0000' と '\u0000' の間の文字リテラルである場合'\u007f' を含めて (§3.10.4)、a と b を p の任意の 2 つのボックス化変換の結果とします。a == b は常にそうです。

個人的に私は使用します:

if (x.intValue() == y.intValue())

また

if (x.equals(y))

あなたが言うように、ラッパー型( など)と数値型( など)の比較ではIntegerLongラッパーintlongの値はボックス化されておらず、関連するプリミティブ値にテストが適用されます。

これは、バイナリ数値昇格の一部として発生します ( JLS セクション 5.6.2 )。個々のオペレーターのドキュメントを見て、それが適用されているかどうかを確認してください。たとえば、 and のドキュメントから==( !=JLS 15.21.1 ):

等価演算子のオペランドが両方とも数値型である場合、または一方が数値型で他方が数値型に変換可能 (§5.1.8) である場合、オペランドに対してバイナリ数値昇格が実行されます (§5.6.2)。

<<=および>( JLS 15.20.1>= )

数値比較演算子の各オペランドの型は、プリミティブ数値型に変換可能な型 (§5.1.8) である必要があります。そうしないと、コンパイル時エラーが発生します。バイナリ数値昇格は、オペランドで実行されます (§5.6.2)。拡張されたオペランドの型が int または long の場合、符号付き整数の比較が実行されます。このプロモートされた型が float または double の場合、浮動小数点比較が実行されます。

どちらの型も数値型ではない状況の一部とは見なされないことに注意してください。

于 2009-10-04T07:10:48.770 に答える
48

==オブジェクトの等価性を引き続きテストします。ただし、だまされやすい:

Integer a = 10;
Integer b = 10;

System.out.println(a == b); //prints true

Integer c = new Integer(10);
Integer d = new Integer(10);

System.out.println(c == d); //prints false

不等式を使用した例は、オブジェクトで定義されていないため機能します。ただし、==比較では、オブジェクトの等価性は引き続きチェックされます。この場合、ボックス化されたプリミティブからオブジェクトを初期化すると、同じオブジェクトが (a と b の両方で) 使用されます。プリミティブ ボックス クラスは不変であるため、これは適切な最適化です。

于 2009-10-03T21:39:49.090 に答える
42

Java 1.7 以降、Objects.equalsを使用できます。

java.util.Objects.equals(oneInteger, anotherInteger);

引数が互いに等しい場合は true を返し、そうでない場合は false を返します。したがって、両方の引数が null の場合は true が返され、引数が 1 つだけ null の場合は false が返されます。それ以外の場合は、最初の引数の equals メソッドを使用して等しいかどうかが判断されます。

于 2018-03-22T14:57:04.207 に答える
10

==ただし、次のようなコードを記述する場合は、参照の等価性をチェックします。

Integer a = 1;
Integer b = 1;

aJava は、との同じ不変オブジェクトを再利用できるほど賢いbので、これは正しいです: a == b. 興味深いことに、Java がこのように最適化を停止する場所を示す小さな例を書きました。

public class BoxingLol {
    public static void main(String[] args) {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            Integer a = i;
            Integer b = i;
            if (a != b) {
                System.out.println("Done: " + i);
                System.exit(0);
            }
        }
        System.out.println("Done, all values equal");
    }
}

これを(自分のマシンで)コンパイルして実行すると、次のようになります。

Done: 128
于 2015-07-15T21:30:13.693 に答える
10

tl;dr私の意見は+、値の等価性をチェックするときにオペランドの1つでボックス化解除をトリガーするために単項を使用し、それ以外の場合は単に数学演算子を使用することです。根拠は次のとおりです。

==の比較Integerは同一性比較であり、通常はプログラマーが望んでいるものではなく、目的は値比較を行うことであると既に述べました。それでも、コードのコンパクトさ、正確さ、および速度の両方の観点から、その比較を最も効率的に行う方法について少し科学を行いました。

私は通常の一連の方法を使用しました:

public boolean method1() {
    Integer i1 = 7, i2 = 5;
    return i1.equals( i2 );
}

public boolean method2() {
    Integer i1 = 7, i2 = 5;
    return i1.intValue() == i2.intValue();
}

public boolean method3() {
    Integer i1 = 7, i2 = 5;
    return i1.intValue() == i2;
}

public boolean method4() {
    Integer i1 = 7, i2 = 5;
    return i1 == +i2;
}

public boolean method5() { // obviously not what we want..
    Integer i1 = 7, i2 = 5;
    return i1 == i2;
}

コンパイルと逆コンパイル後に次のコードを取得しました。

public boolean method1() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    return var1.equals( var2 );
}

public boolean method2() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method3() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method4() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method5() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2 == var1 ) {
        return true;
    } else {
        return false;
    }
}

簡単にわかるように、メソッド 1 はInteger.equals()(明らかに) 呼び出し、メソッド 2 ~ 4 はまったく同じコードになり、 によって値をアンラップし.intValue()てから直接比較します。メソッド 5 は ID 比較をトリガーするだけで、間違った方法です。値を比較します。

(JS などで既に述べたように)equals()オーバーヘッドが発生するため (実行する必要がinstanceofあり、チェックされていないキャスト)、方法 2 ~ 4 はまったく同じ速度で動作し、HotSpot ではないため、タイトなループで使用する場合は方法 1 よりも明らかに優れています。キャスト & を最適化する可能性がありinstanceofます。

他の比較演算子 (例: </ >) と非常によく似ています - それらはボックス化解除をトリガーしますが、使用はしcompareTo()ません - しかし今回は、操作は HS によって高度に最適化さintValue()れます。

私の意見では、めったに使用されないバージョン 4 が最も簡潔な方法です。ベテランの C/Java 開発者ならintでも、ほとんどの場合、単項プラスは/へのキャストに等しいことを知ってい.intValue()ます。単項プラスを使用しないでください)、おそらく最も明確かつ最も簡潔に意図を示しています。これは、オペランドの 1 つの値が必要であり、他の値もボックス化解除することを強制することを示しています。また、プリミティブ値に使用される通常の比較に間違いなく最も似ています。inti1 == i2int

私の投票は、パフォーマンスi1 == +i2と一貫性の両方の理由から、オブジェクトのi1 > i2スタイルに賛成です。Integerまた、型宣言以外は何も変更せずに、コードをプリミティブに移植できるようにします。bigInt.add(10).multiply(-3)名前付きメソッドを使用することは、非常に批判されているスタイルと同様に、セマンティック ノイズを導入するように思えます。

于 2015-05-23T16:52:51.993 に答える
8

通話中

if (a == b)

ほとんどの場合は機能しますが、常に機能するとは限らないため、使用しないでください。

2 つの Integer クラスが等しいかどうかを比較する最も適切な方法は、名前が 'a' と 'b' であると仮定して、次のように呼び出すことです。

if(a != null && a.equals(b)) {
  System.out.println("They are equal");
}

少し高速なこの方法を使用することもできます。

   if(a != null && b != null && (a.intValue() == b.intValue())) {
      System.out.println("They are equal");
    } 

私のマシンでは、990 億回の操作に最初の方法で 47 秒、2 番目の方法で 46 秒かかりました。違いを確認するには、数十億の値を比較する必要があります。

「a」はオブジェクトであるため、null になる可能性があることに注意してください。この方法で比較しても、ヌル ポインター例外は発生しません。

より大きいかより小さいかを比較するには、次を使用します

if (a != null && b!=null) {
    int compareValue = a.compareTo(b);
    if (compareValue > 0) {
        System.out.println("a is greater than b");
    } else if (compareValue < 0) {
        System.out.println("b is greater than a");
    } else {
            System.out.println("a and b are equal");
    }
} else {
    System.out.println("a or b is null, cannot compare");
}
于 2016-09-22T17:55:40.567 に答える