Perché (i <= j && j <= i && i! = J) restituisce TRUE?


104

Ho scritto un pezzo di codice Java che viene eseguito in un ciclo infinito.

Di seguito il codice:

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

Nel codice sopra, mentre si vede la condizione nel whileciclo, all'inizio sembra che quel programma non entrerà nel whileciclo. Ma in realtà è un ciclo infinito e continua a stampare il valore.

Cosa sta succedendo qui?


8
La risposta semplice è che i<=j && j<=i && i!=jquesta condizione viene sempre valutata come vera. Prendi un pezzo di carta e valuta di prenderlo :)
Pradeep Simha

4
Il modo in cui stai creando il numero intero non è corretto. Usa 'compareTo'
nachokk

7
Se non cambi mai io j, quando ti aspetti che il ciclo termini?
Fred Larson

33
@PradeepSimha Per valori int semplici, questo restituirà sempre false . Da i<=je j<=isi può concludere, quello i == j, che contraddice l'ultimo termine. Pertanto l'intera espressione restituisce false e il tempo non viene immesso. Il punto chiave è l'identità dell'oggetto qui!
Sirko

4
Per inciso, questo è il puzzle 32 nel libro Java Puzzlers: Traps, Pitfalls e Corner Cases.
Cyanfish

Risposte:


188
  • i <= jviene valutata a true, a causa di auto unboxing accade per i confronti int e poi entrambi ie jtenere premuto il valore di default, 0.

  • j <= iviene valutato a truecausa del motivo di cui sopra.

  • i != jviene valutato a true, perché entrambi ie jsono oggetti diversi. E durante il confronto degli oggetti, non è necessario unboxing automatico.

Tutte le condizioni sono vere e non stai cambiando ie jin loop, quindi funziona all'infinito.


10
puoi spiegare, perché! = sta controllando l'indice di memoria degli oggetti di riferimento e <= sta controllando il valore non boxed di Integer ?? .. perché c'è una tale differenza tra questi operatori?
Punith Raj

41
Gli operatori @PunithRaj <&> lavorano sulle primitive e non sugli oggetti, quindi per questi operatori avviene l'auto unboxing. Ma gli operatori == e! = Possono essere utilizzati anche per il confronto degli oggetti, quindi non è necessario unboxing qui, quindi gli oggetti vengono confrontati.
Juned Ahsan

14
Ah, i pericoli nascosti della boxe / unboxing implicita !!
Hot Licks

3
Stack Overflow dovrebbe semplicemente aggiungere un nuovo tag, "L'unboxing automatico è stato il più grande errore mai fatto in Java". :-). Fatta eccezione per gli autori dei libri di Java Puzzler. Usalo per taggare domande come queste.
user949300

4
nota che Integer.valueOf(0) == Integer.valueOf(0)viene sempre valutato come vero perché in questo caso viene restituito lo stesso oggetto (vedi IntegerCache grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… )
Vitalii Fedorenko

40

Perché stai confrontando

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true)mentre crei oggetti, non un confronto primitivo. Quindi valuta a while(true) { // Never ending loop }.


2
Ohh! hidden Dragon of auto UNBOXING ... Buona spiegazione.
HybrisHelp

17

Gli oggetti interi sono diversi. È diverso dal tipo int di base.

Vedi questa risposta: come confrontare correttamente due numeri interi in Java?

La i != jparte è vera, che ti aspettavi fosse falsa.


Sebbene sia vero, qui non importa né risponde alla domanda.
Kon

6
@ Kon: In effetti questa è la risposta. Le condizioni # 1 e # 2 vengono valutate a truecausa dell'autoboxing. In caso di # 3 l'autoboxing non si applica e il confronto avviene a livello di oggetto (posizione di memoria).
casa il

1

Il ciclo non finisce perché la tua condizione è vera (i! = J è vera perché ci sono 2 oggetti diversi, usa invece Integer.valueOf) e all'interno del ciclo i valori non cambiano, quindi la tua condizione rimane vera per sempre.


1

Gli oggetti interi sono diversi. È diverso dal tipo int di base. quindi puoi semplicemente fare così. quello che fai è solo confrontare l'oggetto e, naturalmente, il risultato è vero.


1

Ci sono due diversi casi che dobbiamo prima capire,

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

caso 2:

        Integer i = 10;
        Integer j = 10;

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

entrambi sono diversi, come

nel caso 1: i!=jsarà trueperché entrambi fanno riferimento a due oggetti diversi nell'heap e non possono essere uguali. Ma

nel caso 2: i==jsarà trueperché entrambi 10 sono letterali interi e Java mantiene pool for Integer literalsche hanno valore (-128 <= X <= 127). Quindi, in questo caso 10 <= 127 risulta vero, quindi entrambi avranno riferimento allo stesso oggetto.


0

Forse il motivo è che sia "i" che "j" sono oggetti e il confronto degli oggetti non è lo stesso del confronto dei riferimenti agli oggetti. Si prega di considerare l'utilizzo di! I.equals (j) invece di i! = J


0

Il programma continua a visualizzare lo stesso valore di iperché non stai incrementando o decrementando il valore di io j. La condizione in for continua a essere valutata come vera, quindi è un ciclo infinito.


Penso che la domanda riguardasse più la i!=jparte che sorprendentemente restituisce vero e non i <=confronti.
Soravux

0

Intero a = new Integer (0); Intero b = nuovo Intero (0);

I confronti <= e> = useranno il valore unboxed 0, mentre! = Confronterà i riferimenti e avrà esito positivo poiché sono oggetti diversi.

Anche questo funzionerà anche i, e

Intero a = 1000; Intero b = 1000;

ma questo non:

Intero a = 100; Intero b = 100;

Il motivo è perché Integer utilizza internamente la memorizzazione nella cache per oggetti Integer tra -128 e 127 e restituisce istanze da quella cache per l'intervallo che copre. Non ne sono sicuro, ma immagino che tu possa anche modificare il suo valore massimo nel pacchetto "java.lang.Integer.IntegerCache.high".

Per una migliore comprensione, controllare l'URL: https://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


-3

devi sapere che è un po 'diverso in && questo e questo e quando usi && allora quando la prima condizione è vera, controlla la seconda condizione se è falsa quindi non controlla la terza condizione perché in & operator se una condizione è falsa tutte le l'istruzione è falsa se si usa || quindi se è vero, restituisce vero nel codice perché i e j sono uguali, la prima e la seconda condizione sono vere, quindi nella terza condizione sarà falso perché sono uguali e mentre la condizione è falsa.


Non so il motivo per cui la mia risposta ottenere valore miniere, perché la mia risposta è vero vedi questo link il suo vero allora prima di ottenere miniere per la mia risposta continua stackoverflow.com/questions/5564410/difference-between-and
sara Sodagari
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.