(i <= j && j <= i && i!= j)がTRUEと評価されるのはなぜですか?


104

無限ループで実行されるJavaコードを書きました。

以下はコードです:

public class TestProgram {
    public static void main(String[] args){
        Integer i = new Integer(0);
        Integer j = new Integer(0);

        while(i<=j && j<=i && i!=j){
            System.out.println(i);
        }
    }
}

上記のコードでは、whileループ内の条件を見ていると、最初はそのプログラムがwhileループ内に入らないように見えます。しかし、実際にはそれは無限ループであり、値を出力し続けます。

ここで何が起きてるの?


8
簡単な答えは、i<=j && j<=i && i!=jこの条件は常にtrueと評価されることです。ちょうど紙を取り、あなたがそれをキャッチすることを評価してください:)
Pradeep Simha

4
整数の作成方法が正しくありません。「compareTo」を使用
nachokk

7
iまたはを変更しない場合j、ループが終了するのはいつになると思いますか?
Fred Larson

33
@PradeepSimha単純なint値の場合、これは常にfalseになります。からi<=j、そしてj<=iあなたは結論付けることができますi == j、それは最後の用語と矛盾します。したがって、式全体がfalseと評価され、whileは入力されません。ここでのポイントは、オブジェクトのアイデンティティです。
シルコ2013

4
余談ですが、これは本「Java Puzzlers:Traps、Pitfalls、and Corner Cases」のパズル32です。
Cyanfish 2013

回答:


188
  • i <= jはに評価されますtrue。これは、自動ボックス化解除がint比較で発生し、その後両方ijデフォルト値が保持されるためです0

  • j <= itrue以上の理由で評価されます。

  • i != jとは異なるオブジェクトtrueであるため、はに評価されます。また、オブジェクトを比較するときに、自動ボックス化解除の必要はありません。ij

すべての条件が真であり、変更ijループもしていないため、無限に実行されます。


10
!=が参照オブジェクトのメモリインデックスをチェックし、<=がボックス化されていない整数の値をチェックしている理由を説明してください。
Punith Raj 2013

41
@PunithRaj <&>演算子はオブジェクトではなくプリミティブで機能するため、これらの演算子で自動ボックス化解除が行われます。ただし、==および!=演算子はオブジェクトの比較にも使用できるため、ここでボックス化を解除する必要がないため、オブジェクトが比較されます。
Juned Ahsan 2013

14
ああ、暗黙のボクシング/アンボクシングの隠れた危険!!
Hot Licks 2013

3
Stack Overflowは、新しいタグを追加するだけです。「自動ボックス化解除は、Javaでこれまでに発生した最大の間違いです」。:-)。Java Puzzlerの本の著者を除きます。このような質問にタグを付けるために使用します。
user949300 2013

4
Integer.valueOf(0) == Integer.valueOf(0)この場合、同じオブジェクトが返されるため、常にtrueと評価されることに注意してください(IntegerCachegrepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…を参照
Vitalii Fedorenko

40

あなたが比較しているので

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true)プリミティブな比較ではなく、オブジェクトを作成しているとき。したがって、と評価されwhile(true) { // Never ending loop }ます。


2
おお!オートアンボクシングの隠されたドラゴン...良い説明。
HybrisHelp 2013年

17

整数オブジェクトは異なります。基本的なint型とは異なります。

この回答を参照してください:Javaで2つの整数を適切に比較する方法は?

そのi != j部分は真実であり、あなたが偽りであると期待していました。


本当ですが、ここでは関係ありませんし、質問にも答えません。
Kon

6
@近:実際にはこれが答えです。条件#1および#2はtrue、オートボクシングのために評価されます。#3の場合、オートボクシングは適用されず、オブジェクト(メモリロケーション)レベルで比較が行われます。
自宅

1

条件がtrue(2つの異なるオブジェクトがあるためi!= jがtrueであり、代わりにInteger.valueOfを使用)であるためループは終了せず、ループ内では値が変化しないため、条件は永久にtrueのままです。


1

整数オブジェクトは異なります。基本的なint型とは異なります。だからあなたはちょうどそのようにすることができます。あなたがすることはそれは単にオブジェクトを比較することであり、もちろん結果は真です。


1

最初に理解する必要がある2つの異なるケースがあります。

ケース1:

        Integer i = new Integer(10);
        Integer j = new Integer(10);

        System.out.println((i<=j && j<=i && i!=j));
        System.out.println(i!=j);

ケース2:

        Integer i = 10;
        Integer j = 10;

        System.out.println((i<=j && j<=i && i==j));
        System.out.println(i==j);

両方が異なります

ケース1:i!=jtrue、両方がヒープ内の2つの異なるオブジェクトを参照しており、同じにすることはできないためです。だが

ケース2:i==jあろうtrue両方10は、整数リテラルであり、Javaが維持するのでpool for Integer literals値を有します(-128 <= X <= 127)。したがって、この場合は10 <= 127の結果がtrueになるため、両方が同じオブジェクトを参照します。


0

おそらくその理由は、「i」と「j」の両方がオブジェクトであり、オブジェクト比較はオブジェクト参照比較と同じではないためです。i!= jの代わりに!i.equals(j)の使用を検討してください


0

プログラムは、同じ値を表示し続けiますが、インクリメントまたはデクリメントのいずれかの値をされていないためij。forの条件は常にtrueに評価されるため、無限ループになります。


問題は、i!=j驚くべきことに、<=比較ではなく、真と評価される部分に関するものだったと思います。
Soravux 2013

0

整数a = new Integer(0); 整数b =新しいInteger(0);

<=および> =の比較ではボックス化されていない値0が使用されますが、!=は参照を比較し、それらが異なるオブジェクトであるため成功します。

これでも機能します

整数a = 1000; 整数b = 1000;

しかし、これはしません:

整数a = 100; 整数b = 100;

その理由は、Integerが内部的に-128から127までのIntegerオブジェクトのキャッシュを使用し、そのキャッシュから対象範囲のインスタンスを返すためです。わかりませんが、 "java.lang.Integer.IntegerCache.high"パッケージで最大値を変更することもできると思います。

チェックURLをよりよく理解するには、https//www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


-3

&& thisとthis&で少し異なることを知っておく必要があります。 ||を使用すると、ステートメントはfalseになります。次に、trueと表示された場合、iとjが最初に等しく、2番目の条件がtrueであるため、コードでtrueを返し、3番目の条件では、条件がfalseであり、等しいため、falseになります。


私の答えは、鉱山の値を取得し、なぜ私の答えは、このリンクを参照真であるので、私は知らない、その真その後、前に私の答えに地雷が読み得るより多くのstackoverflow.com/questions/5564410/difference-between-and
サラSodagari
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.