Wiem, że jeśli porównasz pierwotną liczbę całkowitą w pudełku ze stałą, taką jak:
Integer a = 4;
if (a < 5)
a
zostanie automatycznie rozpakowane i porównanie będzie działać.
Co jednak dzieje się, gdy porównujesz dwa pola Integers
i chcesz porównać równość lub mniej niż / więcej niż?
Integer a = 4;
Integer b = 5;
if (a == b)
Czy powyższy kod spowoduje sprawdzenie, czy są one tym samym obiektem, czy też w takim przypadku automatycznie się rozpakuje?
Co powiesz na:
Integer a = 4;
Integer b = 5;
if (a < b)
?
java
integer
autoboxing
Shmosel
źródło
źródło
==
zamiastequals
daje poprawny wynik, może to być spowodowane tym, że liczby w ramkach są internowane lub w inny sposób ponownie wykorzystywane (prawdopodobnie jako optymalizacja kompilatora). Powodem, dla którego warto zadać to pytanie, jest ustalenie, co się dzieje wewnętrznie, a nie tego, co się wydaje. (Przynajmniej dlatego tu jestem.)Odpowiedzi:
Nie, == między liczbą całkowitą, długą itd. Sprawdzi, czy istnieje równość odniesienia - tj
to sprawdzi czy
x
iy
odnoszą się do tego samego obiektu , a nie równych przedmiotów.Więc
gwarantuje wydruk
false
. Przenoszenie „małych” wartości autoboxowanych może prowadzić do trudnych wyników:Zostanie wydrukowane
true
, zgodnie z zasadami boksu ( sekcja 5.1.7 JLS ). Nadal używana jest równość referencji, ale autentycznie referencje są równe.Osobiście użyłbym:
lub
Jak można powiedzieć, dla każdego porównania typu otoki (
Integer
,Long
etc) oraz typu liczbowego (int
,long
etc) wartość typu wrapper jest rozpakowanych a test jest stosowany do pierwotnych wartości zaangażowanych.Dzieje się tak w ramach binarnej promocji numerycznej ( sekcja 5.6.2 JLS ). Przejrzyj dokumentację każdego operatora, aby sprawdzić, czy jest zastosowana. Na przykład z dokumentów dla
==
i!=
( JLS 15.21.1 ):i
<
,<=
,>
i>=
( na trasę 15.20.1 )Zwróć uwagę, że żaden z nich nie jest uważany za część sytuacji, w której żaden typ nie jest typem liczbowym.
źródło
x.compareTo(y) < 0
zamiastx < y
?==
nadal będzie testować równość obiektów. Łatwo jest jednak dać się zwieść:Twoje przykłady z nierównościami będą działać, ponieważ nie są zdefiniowane w Obiektach. Jednak przy
==
porównaniu nadal będzie sprawdzana równość obiektów. W takim przypadku po zainicjowaniu obiektów z prymitywu w pudełku używany jest ten sam obiekt (zarówno dla a, jak i b). Jest to optymalna optymalizacja, ponieważ prymitywne klasy pól są niezmienne.źródło
200
, oba testy zostaną wydrukowanefalse
.equals
bycia nazwanym”.Od wersji Java 1.7 możesz używać Objects.equals :
źródło
==
sprawdza równość referencji, jednak podczas pisania kodu takiego jak:Java jest wystarczająco inteligentny, aby używać tego samego niezmiennego dla
a
ib
tak jest to prawdąa == b
. Ciekawe, napisałem mały przykład, aby pokazać, gdzie Java przestaje optymalizować w ten sposób:Kiedy kompiluję i uruchamiam to (na moim komputerze), otrzymuję:
źródło
tl; dr moim zdaniem jest użycie jedności
+
do uruchomienia rozpakowywania na jednym z operandów podczas sprawdzania równości wartości, a po prostu użycie operatorów matematycznych w przeciwnym razie. Uzasadnienie jest następujące:Wspomniano już, że
==
porównanieInteger
to porównanie tożsamości, które zwykle nie jest tym, czego chce programista, a celem jest porównanie wartości; Mimo to zrobiłem trochę nauki o tym, jak zrobić to porównanie najbardziej wydajnie, zarówno pod względem zwięzłości kodu, poprawności i szybkości.Użyłem zwykłej wiązki metod:
i otrzymałem ten kod po kompilacji i dekompilacji:
Jak łatwo zauważyć, wywołania metody 1
Integer.equals()
(oczywiście), metody 2-4 dają dokładnie ten sam kod , rozpakowywanie wartości za pomocą,.intValue()
a następnie bezpośrednie porównywanie, a metoda 5 po prostu uruchamia porównanie tożsamości, ponieważ jest to niewłaściwy sposób porównaj wartości.Ponieważ (jak już wspomniano np. JS)
equals()
powoduje narzut (musi to zrobićinstanceof
i niezaznaczone rzutowanie), metody 2-4 będą działały z dokładnie taką samą prędkością, zauważalnie lepszą niż metoda 1, gdy są używane w ciasnych pętlach, ponieważ HotSpot nie jest prawdopodobnie zoptymalizuje obsady iinstanceof
.Jest całkiem podobny do innych operatorów porównania (np.
<
/>
) - będą wyzwalać rozpakowywanie, podczas gdy używaniecompareTo()
tego nie zrobi - ale tym razem operacja jest wysoce zoptymalizowana przez HS, ponieważintValue()
jest to tylko metoda gettera (główna kandydatka do optymalizacji).Moim zdaniem, rzadko stosowany w wersji 4 jest najbardziej zwięzły sposób - każdy zaprawiony programista C / Java wie, że jednoargumentowy plus to w większości przypadków równa do obsady do
int
/.intValue()
- choć może to być trochę WTF moment dla niektórych (głównie tych, którzy didn nie używają jednoznacznego plusa w ciągu swojego życia), najprawdopodobniej pokazuje intencję najdokładniej i najdokładniej - pokazuje, że chcemyint
wartości jednego z argumentów, zmuszając również drugą wartość do rozpakowania. Jest również bezsprzecznie najbardziej podobny do zwykłegoi1 == i2
porównania stosowanego dla pierwotnychint
wartości.Mój głos dotyczy stylu
i1 == +i2
i obiektów, zarówno ze względu na wydajność, jak i spójność. Dzięki temu kod jest przenośny dla prymitywów, nie zmieniając niczego poza deklaracją typu. Używanie nazwanych metod wydaje mi się wprowadzać do mnie hałas semantyczny, podobny do bardzo krytykowanego stylu.i1 > i2
Integer
bigInt.add(10).multiply(-3)
źródło
unary +
(jednoargumentowy plus), patrz np stackoverflow.com/questions/2624410/...Powołanie
Będzie działać przez większość czasu, ale nie ma gwarancji, że zawsze będzie działać, więc nie używaj go.
Najbardziej właściwym sposobem porównania dwóch klas całkowitych pod kątem równości, przy założeniu, że są one nazwane „a” i „b”, jest wywołanie:
Możesz także użyć tej metody, która jest nieco szybsza.
Na moim komputerze 99 miliardów operacji zajęło 47 sekund przy użyciu pierwszej metody, a 46 sekund przy użyciu drugiej metody. Aby zobaczyć różnicę, musisz porównać miliardy wartości.
Zauważ, że „a” może być zerowe, ponieważ jest to Obiekt. Porównywanie w ten sposób nie spowoduje wyjątku wskaźnika zerowego.
Aby porównać większe i mniejsze niż, użyj
źródło
if (a==b)
działa tylko dla małych wartości i nie będzie działać przez większość czasu.Zawsze powinniśmy stosować metodę equals () do porównywania dwóch liczb całkowitych. Jest to zalecana praktyka.
Jeśli porównamy dwie liczby całkowite przy użyciu ==, to działałoby dla pewnego zakresu wartości liczb całkowitych (liczba całkowita od -128 do 127) ze względu na wewnętrzną optymalizację JVM.
Zobacz przykłady:
Przypadek 1:
W powyższym przypadku JVM używa wartości aib z puli pamięci podręcznej i zwraca tę samą instancję obiektu (a więc adres pamięci) obiektu liczb całkowitych i otrzymujemy oba są równe. Jest to optymalizacja JVM dla pewnych wartości zakresu.
Przypadek 2: W tym przypadku aib nie są równe, ponieważ nie ma zakresu od -128 do 127.
Właściwy sposób:
Mam nadzieję, że to pomoże.
źródło
W moim przypadku musiałem porównać dwa
Integer
dla równości tam, gdzie mogłyby być obienull
. Szukano podobnego tematu, nie znalazłem nic eleganckiego do tego. Przyszedł z prostymi funkcjami narzędziowymi.źródło
Ponieważ metoda porównania musi być wykonana w oparciu o typ int (x == y) lub klasę Integer (x.equals (y)) z odpowiednim operatorem
źródło
ta metoda porównuje dwie liczby całkowite z zerowym sprawdzaniem, patrz testy
źródło
Objects.equals(x,y)
metody zamiast własnej.