Warum wird (i <= j && j <= i && i! = J) als WAHR bewertet?

104

Ich habe einen Java-Code geschrieben, der in einer Endlosschleife ausgeführt wird.

Unten ist der Code:

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);
        }
    }
}

Im obigen Code whilesieht es zunächst so aus, als würde das Programm nicht in die Schleife gelangen , obwohl die Bedingung in der Schleife whileangezeigt wird. Aber eigentlich ist es eine Endlosschleife und druckt den Wert weiter.

Was passiert hier?

Kshitij Jain
quelle
8
Einfache Antwort ist, dass i<=j && j<=i && i!=jdiese Bedingung immer als wahr ausgewertet wird. Nehmen Sie einfach ein Stück Papier und bewerten Sie, ob Sie es fangen werden :)
Pradeep Simha
4
Die Art und Weise, wie Sie eine Ganzzahl erstellen, ist falsch. Verwenden Sie 'compareTo'
nachokk
7
Wenn Sie sich nie ändern ioder jwann würden Sie erwarten, dass die Schleife endet?
Fred Larson
33
@PradeepSimha Bei einfachen int-Werten würde dies immer false ergeben . Von i<=jund j<=iSie können feststellen, dass i == j, was den letzten Begriff widerspricht. Somit wird der gesamte Ausdruck als falsch ausgewertet und die Weile würde nicht eingegeben. Entscheidend ist hier die Objektidentität!
Sirko
4
Abgesehen davon ist dies Puzzle 32 im Buch Java Puzzlers: Fallen, Fallstricke und Eckfälle.
Cyanfish

Antworten:

188
  • i <= jwird ausgewertet true, da das automatische Entpacken für int-Vergleiche und dann für beide erfolgt iund jder Standardwert beibehalten wird 0.

  • j <= iwird trueaus dem oben genannten Grund ausgewertet .

  • i != jwird ausgewertet true, weil beide iund junterschiedliche Objekte sind. Beim Vergleichen von Objekten ist kein automatisches Entpacken erforderlich.

Alle Bedingungen sind wahr, und Sie ändern sich nicht iund befinden sich jin einer Schleife, sodass es unendlich läuft.

Juned Ahsan
quelle
10
Können Sie bitte erklären, warum! = nach dem Speicherindex von Referenzobjekten und <= nach dem Wert von Integer ohne Box sucht? Warum gibt es einen solchen Unterschied zwischen diesen Operatoren?
Punith Raj
41
@ PunithRaj <&> -Operatoren arbeiten mit Grundelementen und nicht mit Objekten. Daher erfolgt das automatische Entpacken für diese Operatoren. Die Operatoren == und! = Können jedoch auch für den Objektvergleich verwendet werden, sodass hier kein Unboxing erforderlich ist. Daher werden Objekte verglichen.
Juned Ahsan
14
Ah, die versteckten Gefahren des impliziten Boxens / Unboxing !!
Hot Licks
3
Stack Overflow sollte nur ein neues Tag hinzufügen: "Auto-Unboxing war der größte Fehler, der jemals in Java gemacht wurde". :-). Mit Ausnahme der Autoren der Java Puzzler-Bücher. Verwenden Sie es, um Fragen wie diese zu markieren.
user949300
4
Beachten Sie, dass Integer.valueOf(0) == Integer.valueOf(0)immer als wahr ausgewertet wird, da in diesem Fall dasselbe Objekt zurückgegeben wird (siehe IntegerCache grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… )
Vitalii Fedorenko
40

Weil du vergleichst

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true)Während Sie Objekte erstellen, kein primitiver Vergleich. Also wertet es aus while(true) { // Never ending loop }.

Ashwani
quelle
2
Ohh! versteckter Drache des automatischen Entpackens ... Gute Erklärung.
HybrisHelp
17

Die ganzzahligen Objekte sind unterschiedlich. Es unterscheidet sich vom grundlegenden int-Typ.

Siehe diese Antwort: Wie vergleiche ich zwei Ganzzahlen in Java richtig?

Der i != jTeil ist wahr, von dem Sie erwartet hatten, dass er falsch ist.

Oberst Panik
quelle
Es ist zwar wahr, aber es spielt hier keine Rolle und beantwortet auch nicht die Frage.
Kon
6
@Kon: In der Tat ist dies die Antwort. Die Bedingungen Nr. 1 und Nr. 2 werden trueaufgrund von Autoboxing ausgewertet . Im Fall von # 3 gilt kein Autoboxing und der Vergleich erfolgt auf Objektebene (Speicherort).
Hause
1

Die Schleife endet nicht, weil Ihre Bedingung wahr ist (i! = J ist wahr, weil es 2 verschiedene Objekte gibt, verwenden Sie stattdessen Integer.valueOf) und innerhalb der Schleife ändern sich die Werte nicht, sodass Ihre Bedingung für immer wahr bleibt.

Silviu Burcea
quelle
1

Die ganzzahligen Objekte sind unterschiedlich. Es unterscheidet sich vom grundlegenden int-Typ. so kannst du es einfach machen. Was Sie tun, ist nur das Objekt zu vergleichen und natürlich ist das Ergebnis wahr.

Krichevskoy
quelle
1

Es gibt zwei verschiedene Fälle, die wir zuerst verstehen müssen:

Fall 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);

Fall 2:

        Integer i = 10;
        Integer j = 10;

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

beide sind unterschiedlich, wie

in Fall 1: i!=jliegt daran, truedass beide auf zwei verschiedene Objekte im Heap verweisen und nicht gleich sein können. Aber

in Fall 2: i==jliegt daran, truedass beide 10 ganzzahlige Literale sind und Java verwaltet pool for Integer literals, die Wert haben (-128 <= X <= 127). In diesem Fall sind also 10 <= 127 wahr. Beide beziehen sich also auf dasselbe Objekt.

Akhilesh Dhar Dubey
quelle
0

Vielleicht liegt der Grund darin, dass sowohl 'i' als auch 'j' Objekte sind und der Objektvergleich nicht mit dem Objektreferenzvergleich identisch ist. Bitte verwenden Sie! I.equals (j) anstelle von i! = J.

Eric Gopak
quelle
0

Das Programm hält auf den gleichen Wert darstellen kann, iweil Sie nicht erhöht oder verringert entweder der Wert ioder j. Die Bedingung im for wird immer als wahr ausgewertet, es handelt sich also um eine Endlosschleife.

user28646
quelle
Ich denke, die Frage bezog sich eher auf den i!=jTeil, der überraschenderweise als wahr bewertet wird, und nicht auf die <=Vergleiche.
Soravux
0

Ganzzahl a = neue Ganzzahl (0); Ganzzahl b = neue Ganzzahl (0);

Die Vergleiche <= und> = verwenden den unboxed-Wert 0, während! = Die Referenzen vergleicht und erfolgreich ist, da es sich um unterschiedliche Objekte handelt.

Auch das wird auch funktionieren, z

Ganzzahl a = 1000; Ganzzahl b = 1000;

aber das geht nicht:

Ganzzahl a = 100; Ganzzahl b = 100;

Der Grund dafür ist, dass Integer intern das Caching für Integer-Objekte zwischen -128 und 127 verwendet und Instanzen aus diesem Cache für den abgedeckten Bereich zurückgibt. Ich bin nicht sicher, aber ich denke, Sie können den Maximalwert auch im Paket "java.lang.Integer.IntegerCache.high" ändern.

Zum besseren Verständnis überprüfen Sie die URL: https://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching

Waheed
quelle
-3

Sie müssen wissen, dass es in && this und this & etwas anders ist. Wenn Sie && verwenden, dann, wenn die erste Bedingung wahr ist, dann prüft es die zweite Bedingung, wenn es falsch ist, dann prüft es nicht die dritte Bedingung, weil in & operator, wenn eine Bedingung falsch ist, alle Anweisung ist falsch, wenn || verwendet wird Wenn es dann true sieht, gibt es in Ihrem Code true zurück, weil i und j gleich sind. Erste und zweite Bedingung sind wahr. In der dritten Bedingung ist es falsch, weil sie gleich sind und während Bedingung falsch ist.

Sara Sodagari
quelle
Ich weiß nicht, warum meine Antwort Minenwert erhält, weil meine Antwort wahr ist. Sehen Sie, dass dieser Link wahr ist, bevor Sie Minen zu meiner Antwort erhalten. Lesen Sie mehr stackoverflow.com/questions/5564410/difference-between-and
sara Sodagari