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?


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.


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 }.


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.


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.


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.


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.


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.


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.


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


-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.


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.