Dlaczego (i <= j && j <= i && i! = J) przyjmuje wartość PRAWDA?


104

Napisałem fragment kodu Java, który działa w nieskończonej pętli.

Poniżej kod:

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

W powyższym kodzie, widząc warunek w whilepętli, na początku wygląda na to, że program nie wejdzie do whilepętli. Ale w rzeczywistości jest to nieskończona pętla i nadal drukuje wartość.

Co tu się dzieje?


8
Prosta odpowiedź jest i<=j && j<=i && i!=jtaka, że ​​warunek ten zawsze jest prawdziwy. Po prostu weź kawałek papieru i oceń, że złapiesz :)
Pradeep Simha

4
Sposób tworzenia liczby całkowitej jest nieprawidłowy. Użyj „compareTo”
nachokk

7
Jeśli nigdy się nie zmienisz ilub jkiedy spodziewasz się zakończenia pętli?
Fred Larson

33
@PradeepSimha W przypadku prostych wartości int zawsze dawałoby to fałsz . Z i<=ji j<=imożna wywnioskować, że jest to i == jsprzeczne z ostatnim terminem. W ten sposób całe wyrażenie przyjmuje wartość false, a while nie zostałby wprowadzony. Kluczową kwestią jest tutaj tożsamość obiektu!
Sirko,

4
Na marginesie, jest to zagadka 32 w książce Java Puzzlers: Traps, Pitfalls, and Corner Cases.
Cyanfish

Odpowiedzi:


188
  • i <= jocenia się true, bo auto unboxing zdarza int porównań, a następnie oba ii jposiadają wartość domyślną 0.

  • j <= ijest oceniany z truepowodu powyższego powodu.

  • i != jjest oceniany do true, ponieważ oba ii jsą różnymi obiektami. Porównując obiekty, nie ma potrzeby automatycznego rozpakowywania.

Wszystkie warunki są spełnione, a ty nie zmieniasz się ii nie jzapętlasz, więc działa w nieskończoność.


10
czy możesz wyjaśnić, dlaczego! = sprawdza indeks pamięci obiektów referencyjnych, a <= sprawdza nieopakowaną wartość liczby całkowitej ?? .. dlaczego jest taka różnica między tymi operatorami?
Punith Raj

41
Operatory @PunithRaj <&> działają na prymitywach, a nie na obiektach, stąd automatyczne rozpakowywanie ma miejsce dla tych operatorów. Ale operatory == i! = Mogą być również używane do porównywania obiektów, więc nie ma potrzeby rozpakowywania w tym miejscu, dlatego obiekty są porównywane.
Juned Ahsan

14
Ach, ukryte niebezpieczeństwa niejawnego boxingu / unboxingu !!
Hot Licks

3
Stack Overflow powinno po prostu dodać nowy tag: „Automatyczne rozpakowywanie było największym błędem, jaki kiedykolwiek popełniono w Javie”. :-). Z wyjątkiem autorów książek Java Puzzler. Użyj go do oznaczenia takich pytań.
user949300,

4
zauważ, że Integer.valueOf(0) == Integer.valueOf(0)jest zawsze oceniane jako prawda, ponieważ w tym przypadku ten sam obiekt jest zwracany (patrz IntegerCache grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/ ... )
Vitalii Fedorenko

40

Ponieważ porównujesz

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true)gdy tworzysz obiekty, a nie prymitywne porównanie. Więc to ocenia while(true) { // Never ending loop }.


2
Ohh! ukryty smok auto UNBOXING ... Dobre wyjaśnienie.
HybrisHelp

17

Obiekty typu integer są różne. Różni się od podstawowego typu int.

Zobacz odpowiedź: Jak poprawnie porównać dwie liczby całkowite w Javie?

Ta i != jczęść jest prawdą, której spodziewałeś się być fałszywy.


Chociaż to prawda, nie ma to tutaj znaczenia ani nie odpowiada na pytanie.
Kon

6
@Kon: Właściwie to jest odpowiedź. Warunki # 1 i # 2 są oceniane z truepowodu autoboxingu. W przypadku # 3 autobox nie ma zastosowania, a porównanie odbywa się na poziomie obiektu (lokalizacji w pamięci).
dom

1

Pętla nie kończy się, ponieważ twój warunek jest prawdziwy (i! = J jest prawdziwy, ponieważ istnieją 2 różne obiekty, użyj zamiast tego Integer.valueOf), a wewnątrz pętli wartości się nie zmieniają, więc twój warunek pozostaje prawdziwy na zawsze.


1

Obiekty typu integer są różne. Różni się od podstawowego typu int. więc możesz tak po prostu zrobić. co robisz, to po prostu porównuj obiekt i oczywiście wynik jest prawdziwy.


1

Istnieją dwa różne przypadki, które musimy najpierw zrozumieć,

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

przypadek 2:

        Integer i = 10;
        Integer j = 10;

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

oba są różne, jak

w przypadku 1: i!=jbędzie, trueponieważ oba odnoszą się do dwóch różnych obiektów w stercie i nie mogą być takie same. Ale

w przypadku 2: i==jbędzie, trueponieważ oba 10 są literałami całkowitymi, a Java utrzymuje, pool for Integer literalsktóre mają wartość (-128 <= X <= 127). Tak więc w tym przypadku 10 <= 127 wyników jest prawdziwe, więc oba będą miały odniesienie do tego samego obiektu.


0

Być może powodem jest to, że zarówno „i”, jak i „j” są obiektami, a porównanie obiektów to nie to samo, co porównanie odniesień do obiektów. Rozważ użycie! I.equals (j) zamiast i! = J


0

Program wyświetla tę samą wartość, iponieważ nie zwiększasz ani nie zmniejszasz wartości iani j. Warunek w for zawsze oblicza wartość true, więc jest to nieskończona pętla.


Myślę, że pytanie dotyczyło bardziej i!=jczęści, która w zaskakujący sposób ocenia jako prawdziwą, a nie <=porównania.
Soravux

0

Integer a = nowa Integer (0); Integer b = new Integer (0);

Porównania <= i> = użyją wartości 0 bez opakowania, podczas gdy! = Porówna odniesienia i zakończy się powodzeniem, ponieważ są to różne obiekty.

Nawet to zadziała, tj

Liczba całkowita a = 1000; Liczba całkowita b = 1000;

ale to nie:

Liczba całkowita a = 100; Liczba całkowita b = 100;

Powodem jest to, że Integer wewnętrznie używa buforowania dla obiektów Integer między -128 a 127 i zwraca wystąpienia z tej pamięci podręcznej dla zakresu, który obejmuje. Nie jestem pewien, ale myślę, że możesz również zmienić jego maksymalną wartość w pakiecie „java.lang.Integer.IntegerCache.high”.

Aby lepiej zrozumieć, sprawdź adres URL: https://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


-3

musisz wiedzieć, że jest trochę inny w && this i this & kiedy używasz && wtedy, gdy pierwszy warunek jest prawdziwy, wtedy sprawdza drugi warunek, czy jest fałszywy, to nie sprawdza trzeciego warunku, ponieważ w operatorze &, jeśli jeden warunek jest fałszywy, wszystkie instrukcja jest fałszywa, jeśli używasz || wtedy, jeśli widzi prawdę, zwróci prawdę w twoim kodzie, ponieważ i i j jest równe pierwszy, a drugi warunek jest prawdziwy, a następnie w trzecim stanie będzie fałszywy, ponieważ są równe, a warunek jest fałszywy.


nie wiem, dlaczego moja odpowiedź ma wartość mines, ponieważ moja odpowiedź jest prawdziwa, zobacz ten link jest prawdziwy, a potem zanim otrzymam miny do mojej odpowiedzi przeczytaj więcej stackoverflow.com/questions/5564410/difference-between-and
sara Sodagari
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.