Pourquoi (i <= j && j <= i && i! = J) est-il VRAI?

104

J'ai écrit un morceau de code Java qui s'exécute dans une boucle infinie.

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

Dans le code ci-dessus, tout en voyant la condition dans la whileboucle, il semble au début que ce programme n'ira pas à l'intérieur de la whileboucle. Mais en fait, c'est une boucle infinie et continue à imprimer la valeur.

Que se passe-t-il ici?

Kshitij Jain
la source
8
La réponse simple est que i<=j && j<=i && i!=jcette condition est toujours évaluée comme vraie. Il suffit de prendre un morceau de papier et d'évaluer, vous l'attraperez :)
Pradeep Simha
4
La façon dont vous créez un entier est incorrecte. Utilisez 'compareTo'
nachokk
7
Si vous ne changez jamais iou j, quand vous attendez-vous à ce que la boucle se termine?
Fred Larson le
33
@PradeepSimha Pour les valeurs int simples, cela donnerait toujours false . De i<=jet j<=ivous pouvez conclure, cela i == j, ce qui contredit le dernier terme. Ainsi, l'expression entière est évaluée à false et le while ne serait pas entré. Le point clé est l'identité de l'objet ici!
Sirko le
4
En passant, il s'agit du puzzle 32 du livre Java Puzzlers: Traps, Pitfalls, and Corner Cases.
Cyanfish

Réponses:

188
  • i <= jest évaluée à true, parce que unboxing automatique se produit pour des comparaisons int, puis à la fois iet jmaintenir la valeur par défaut, 0.

  • j <= iest évalué en trueraison de la raison ci-dessus.

  • i != jest évalué à true, car les deux iet jsont des objets différents. Et tout en comparant des objets, il n'est pas nécessaire de déballer automatiquement.

Toutes les conditions sont vraies, et vous ne changez pas iet jen boucle, donc il fonctionne à l'infini.

Juned Ahsan
la source
10
pouvez-vous s'il vous plaît expliquer, pourquoi! = vérifie l'index de mémoire des objets de référence et <= vérifie la valeur non encadrée de Integer ?? .. pourquoi il y a une telle différence entre ces opérateurs?
Punith Raj le
41
Les opérateurs @PunithRaj <&> fonctionnent sur les primitives et non sur les objets, d'où le déballage automatique se produit pour ces opérateurs. Mais les opérateurs == et! = Peuvent également être utilisés pour la comparaison d'objets, donc pas besoin de déballer ici, donc les objets sont comparés.
Juned Ahsan le
14
Ah, les dangers cachés de la boxe / unboxing implicite !!
Hot Licks le
3
Stack Overflow devrait simplement ajouter une nouvelle balise, "le déballage automatique a été la plus grosse erreur jamais commise en Java". :-). Sauf pour les auteurs des livres Java Puzzler. Utilisez-le pour marquer des questions comme celles-ci.
user949300
4
notez qu'il Integer.valueOf(0) == Integer.valueOf(0)est toujours évalué à vrai car dans ce cas, le même objet est renvoyé (voir IntegerCache grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… )
Vitalii Fedorenko
40

Parce que vous comparez

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true)comme vous créez des objets, pas une comparaison primitive. Donc, il évalue while(true) { // Never ending loop }.

Ashwani
la source
2
Ohh! Dragon caché de l'auto UNBOXING ... Bonne explication.
HybrisHelp
17

Les objets entiers sont différents. Il est différent du type int de base.

Voir cette réponse: Comment comparer correctement deux nombres entiers en Java?

La i != jpartie est vraie, ce que vous vous attendiez à être faux.

Colonel Panic
la source
Bien que cela soit vrai, cela n'a pas d'importance ici et ne répond pas à la question.
Kon
6
@Kon: En fait, c'est la réponse. Les conditions n ° 1 et n ° 2 sont évaluées en trueraison de la détection automatique. Dans le cas du n ° 3, l'autoboxing ne s'applique pas et la comparaison a lieu au niveau de l'objet (emplacement mémoire).
domicile le
1

La boucle ne se termine pas car votre condition est vraie (i! = J est vraie car il y a 2 objets différents, utilisez plutôt Integer.valueOf) et à l'intérieur de la boucle les valeurs ne changent pas, donc votre condition reste vraie pour toujours.

Silviu Burcea
la source
1

Les objets entiers sont différents. Il est différent du type int de base. donc vous pouvez faire comme ça. ce que vous faites, c'est simplement comparer l'objet et bien sûr le résultat est vrai.

Krichevskoy
la source
1

Il y a deux cas différents que nous devons d'abord comprendre,

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

cas 2:

        Integer i = 10;
        Integer j = 10;

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

les deux sont différents, car

dans le cas 1: i!=jsera trueparce que les deux font référence à deux objets différents dans le tas et ne peuvent pas être identiques. Mais

dans le cas 2: i==jsera trueparce que les deux 10 sont des littéraux entiers et Java maintient pool for Integer literalsqui ont une valeur (-128 <= X <= 127). Donc, dans ce cas, 10 <= 127 résultats vrais, donc les deux auront référence au même objet.

Akhilesh Dhar Dubey
la source
0

La raison en est peut-être que «i» et «j» sont des objets et que la comparaison d'objets n'est pas la même chose que la comparaison de références d'objets. Veuillez envisager d'utiliser! I.equals (j) au lieu de i! = J

Eric Gopak
la source
0

Le programme continue d'afficher la même valeur de iparce que vous n'incrémentez ni ne décrémentez la valeur de iou j. La condition dans for continue à être évaluée à true, il s'agit donc d'une boucle infinie.

user28646
la source
Je pense que la question portait davantage sur la i!=jpartie qui est étonnamment vraie et non sur les <=comparaisons.
Soravux
0

Entier a = nouvel Entier (0); Entier b = nouvel Entier (0);

Les comparaisons <= et> = utiliseront la valeur sans boîte 0, tandis que le! = Comparera les références et réussira car ce sont des objets différents.

Même cela fonctionnera aussi i, e

Entier a = 1000; Entier b = 1000;

mais cela ne fonctionne pas:

Entier a = 100; Entier b = 100;

La raison en est que Integer utilise en interne la mise en cache pour les objets Integer entre -128 et 127 et renvoie les instances de ce cache pour la plage qu'il couvre. Je ne suis pas sûr mais je suppose que vous pouvez également modifier sa valeur maximale dans le package "java.lang.Integer.IntegerCache.high".

Pour une meilleure compréhension, vérifiez l'URL: https://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching

Waheed
la source
-3

vous devez savoir que c'est un peu différent dans && ceci et ceci & quand vous utilisez && alors quand la première condition est vraie alors il vérifie la deuxième condition si c'est faux alors il n'a pas vérifié la troisième condition parce que dans l'opérateur & si une condition est fausse tout le la déclaration est fausse si utiliser || alors s'il voit vrai alors il retourne vrai dans votre code parce que i et j sont égaux, la première et la deuxième condition sont vraies alors dans la troisième condition, elles seront fausses parce qu'elles sont égales et tandis que la condition est fausse.

sara Sodagari
la source
Je ne sais pas pourquoi ma réponse a de la valeur parce que ma réponse est vraie voir ce lien c'est vrai, puis avant d'obtenir les mines de ma réponse lire la suite stackoverflow.com/questions/5564410/difference-between-and
sara Sodagari