2010-09-03 32 views
106

Od wersji Java 1.5 w wielu sytuacjach można w dużym stopniu wymieniać Integer z int.Java: Integer jest równy vs. ==

Jednak znalazłem potencjalną wadę w moim kodzie, która mnie trochę zaskoczyła.

Poniższy kod:

Integer cdiCt = ...; 
Integer cdsCt = ...; 
... 
if (cdiCt != null && cdsCt != null && cdiCt != cdsCt) 
    mismatch = true; 

wydawało się być nieprawidłowo ustalone niedopasowanie, gdy wartości były równe, chociaż nie mogę określić, w jakich okolicznościach. Ustawiłem punkt przerwania w Eclipse i zauważyłem, że wartości Integer są zarówno 137, jak i sprawdziłem wyrażenie boolowskie i powiedziałem, że jest to fałsz, ale kiedy przekroczyłem to ustawienie było niezgodne z ustawieniem true.

Zmiana warunkowy do:

if (cdiCt != null && cdsCt != null && !cdiCt.equals(cdsCt)) 

rozwiązaniu problemu.

Czy ktoś może rzucić trochę światła na to, dlaczego tak się stało? Do tej pory widziałem tylko zachowanie na moim localhost na moim własnym komputerze. W tym konkretnym przypadku kod zakończył pomyślnie około 20 porównań, ale zakończył się niepowodzeniem. Problem był powtarzalny.

Jeśli jest to powszechny problem, powinien powodować błędy w innych naszych środowiskach (dev i test), ale jak dotąd nikt nie zgłosił problemu po setkach testów wykonujących ten fragment kodu.

Czy nadal nie jest uzasadnione korzystanie z == do porównywania dwóch wartości Integer?

Oprócz wszystkich dokładnych odpowiedzi poniżej, poniższy link Stackoverflow ma sporo dodatkowych informacji. To rzeczywiście byłby odpowiedział na moje pierwotne pytanie, ale ponieważ nie wspominając autoboxing na moje pytanie, to nie pojawi się w wybranych sugestii:

Why can't the compiler/JVM just make autoboxing “just work”?

Odpowiedz

177

JVM buforuje wartości całkowite. == działa tylko dla liczb pomiędzy -128 i 127 http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching

+1

Dzięki, to z pewnością wyjaśnia, dlaczego 137 zawodzi! Odpowiada również na moje pytanie o to, dlaczego nie jest to powszechny problem, w 95% przypadków, w których napotkam, wartość będzie mniejsza niż 127. Dobrze jest teraz to złapać, ale za 5% tam, gdzie nie jest. –

+0

Interesująca notatka: aż do kilku tygodni temu, cdiCt i cdsCt były zarówno intami, więc to było w porządku, ale musiałem zrobić ich Integers w celu sprawdzenia sytuacji zerowej, która jest obsługiwana inaczej ... –

+2

@Jeremy Tak, jest to dość niejasny problem, ale z reguły używasz .equals() dla Objects i == dla prymitywów. Nie możesz polegać na autounboxingu w testach równości. – Adam

5

Problem jest to, że dwa obiekty są Integer tylko to, obiekty. Nie pasują, ponieważ porównujesz dwa odniesienia do obiektów, a nie wartości wewnątrz. Oczywiście .equals jest przesłonięte, aby zapewnić porównanie wartości w przeciwieństwie do porównania odniesień do obiektu.

+0

dobra odpowiedź, ale to nie wyjaśnia, dlaczego jest tylko dla braku 137. –

+0

Doh, brakowało mi tej części. – MattC

4

Integer odnosi się do odniesienia, to znaczy porównując odniesienia, które porównujesz, jeśli wskazują na ten sam obiekt, a nie wartość. Stąd pojawia się problem. Powodem, dla którego działa tak dobrze ze zwykłymi typami int jest to, że rozpakowuje wartość zawartą w Integer.

Czy mogę dodać, że jeśli robisz to, co robisz, dlaczego na początek ma się wypowiedzieć if?

mismatch = (cdiCt != null && cdsCt != null && !cdiCt.equals(cdsCt)); 
+2

Dobrze, ale nie robię tego, co robię. To było uproszczone. –

+0

W ten sposób powinien zostać napisany kod i powinna to być zaakceptowana odpowiedź. ** Zawsze ** porównuj obiekty z .equals(). Po co używać buforowanych liczb całkowitych i pozostawić swój kod przypadkiem? – NobleUplift

61

Nie można porównać dwa Integer z prostym == że jesteśmy przedmiotów więc większość odniesień czasowych nie będą takie same.

Istnieje sztuczka, z Integer między -128 a 127, odniesienia będą takie same, jak autoboxing używa Integer.valueOf(), który buforuje małe liczby całkowite.

Jeśli wartość p jest zapakowane jest prawdziwe, fałszywe, bajt, char w zakres \ u0000 do \ u007f lub int lub krótki numer pomiędzy -128 i 127, pozwól R1 i R2 być wyniki dowolnych dwóch konwersji bokserskich na s. Zawsze jest tak, że r1 == r2.


Zasoby:

na ten sam temat:

+0

Dzięki, zaznaczyłem pierwszą odpowiedź jako prawą. –

+0

oh, myślę, że mogę oznaczyć je jako prawidłowe. Sprawdź także znak dla ciebie. –

+0

@Jeremy, właściwie możesz oznaczyć tylko jeden jako właściwy. Kliknięcie znacznika wyboru po raz drugi zmienia tylko zaakceptowaną odpowiedź. Nie być małostkowym; Odpowiedź Colina jest znakomita. :) – Adam

1

"==" zawsze porównuj lokalizację pamięci lub odniesienia do obiektu wartości. metoda równości zawsze porównuj wartości. Ale równa się również pośrednio używa operatora "==" do porównywania wartości.

Integer używa pamięci podręcznej Integer do przechowywania wartości od -128 do +127. Jeśli do sprawdzenia wartości od -128 do 127 używany jest operator ==, to zwraca on wartość true. dla wartości innych niż te zwraca wartość false.

Skierować link jakiegoś dodatkowego informacji