Porównanie wartości długich w pudełkach 127 i 128

111

Chcę porównać dwie wartości Long obiektów przy użyciu ifwarunków. Gdy te wartości są mniejsze niż 128 , ifwarunek działa poprawnie, ale gdy są większe lub równe 128 , porównanie kończy się niepowodzeniem.

Przykład:

Long num1 = 127;
Long num2 = 127;

if (num1 == num2) {
    // Works ok
}

Porównanie w powyższym kodzie działa poprawnie, ale kończy się niepowodzeniem w poniższym kodzie:

Long num1 = 128;
Long num2 = 128;

if (num1 == num2) {
    // Does NOT work
}

Dlaczego istnieje problem z porównywaniem zmiennych typu Long z wartościami większymi niż 127 ? Jeśli zmienne typy danych zostaną zmienione na długie prymitywy , wtedy porównania będą działać we wszystkich przypadkach.

Viraj Dhamal
źródło

Odpowiedzi:

212

TL; DR

Java buforuje wystąpienia w postaci liczb całkowitych od -128do 127. Ponieważ używasz ==do porównywania odwołań do obiektów zamiast wartości , będą pasować tylko obiekty z pamięci podręcznej. Możesz albo pracować z longrozpakowanymi wartościami pierwotnymi, albo używać ich .equals()do porównywania Longobiektów.

Wersja długa (gra słów)

Dlaczego jest problem z porównaniem zmiennej Long z wartością większą niż 127? Jeśli typ danych powyższej zmiennej jest pierwotny (długi), kod działa dla wszystkich wartości.

Java buforuje instancje obiektów typu Integer z zakresu od -128 do 127 . To mówi:

  • Jeśli ustawisz na N Long zmienne wartość 127( buforowana ), ta sama instancja obiektu będzie wskazywana przez wszystkie odwołania. (N zmiennych, 1 instancja)
  • Jeśli ustawisz wartość N Long zmiennych 128( nie buforowaną ), będziesz mieć instancję obiektu wskazywaną przez każde odwołanie. (N zmiennych, N wystąpień)

Dlatego to:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2);

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4);

Wyprowadza to:

prawda
fałsz

W przypadku wartości 127L , ponieważ oba odwołania (wart1 i wart2) wskazują na tę samą instancję obiektu w pamięci (w pamięci podręcznej), zwraca true.

Z drugiej strony, dla wartości 128 , ponieważ nie ma dla niej instancji w pamięci podręcznej, tworzony jest nowy dla każdego nowego przypisania dla wartości w pudełku, co powoduje dwie różne instancje (wskazywane przez val3 i val4) i powraca falsedo porównanie między nimi.

Dzieje się tak wyłącznie dlatego, że z operatorem porównujesz dwa Long odwołania do obiektów , a nie longwartości pierwotne ==. Gdyby nie ten mechanizm pamięci podręcznej, te porównania zawsze kończyłyby się niepowodzeniem, więc prawdziwym problemem jest tutaj porównanie wartości pudełkowych z ==operatorem.

Zmiana tych zmiennych na longtypy prymitywne zapobiegnie temu, ale w przypadku, gdy musisz zachować swój kod przy użyciu Longobiektów, możesz bezpiecznie dokonać tych porównań, stosując następujące podejścia:

System.out.println(val3.equals(val4));                     // true
System.out.println(val3.longValue() == val4.longValue());  // true
System.out.println((long)val3 == (long)val4);              // true

(Konieczne jest właściwe sprawdzenie zerowe, nawet w przypadku odlewów)

IMO , zawsze dobrze jest trzymać się metod .equals () podczas porównywania obiektów.

Linki referencyjne:

Everton
źródło
15

Java buforuje wartości pierwotne od -128 do 127 . Kiedy porównujemy dwa obiekty Long, wewnętrznie typ java rzutuje na wartość pierwotną i porównuje. Ale powyżej 127 obiekt Long nie otrzyma kasty typu. Java buforuje dane wyjściowe za pomocą metody .valueOf () .

To buforowanie działa dla bajtów, krótkich, długich od -128 do 127. W przypadku buforowania typu Integer działa od -128 do java.lang.Integer.IntegerCache.high lub 127, w zależności od tego, która z tych wartości jest większa. (Możemy ustawić wartość najwyższego poziomu do której powinien zostać zapisany w pamięci podręcznej za pomocą java.lang.Integer.IntegerCache.high).

 For example:
    If we set java.lang.Integer.IntegerCache.high=500;
    then values from -128 to 500 will get cached and 

    Integer a=498;
    Integer b=499;
    System.out.println(a==b)

    Output will be "true".

Obiekty Float i Double nigdy nie są buforowane.

Postać otrzyma cache od 0 do 127

Porównujesz dwa obiekty. so == operator sprawdzi równość odniesień do obiektów. Można to zrobić na kilka sposobów.

1) typ rzutuj oba obiekty na wartości pierwotne i porównaj

    (long)val3 == (long)val4

2) odczytaj wartość obiektu i porównaj

    val3.longValue() == val4.longValue()

3) Użyj metody equals () do porównania obiektów.

    val3.equals(val4);  
Sójka
źródło
14

num1i num2są długimi obiektami. Powinieneś użyć equals()do ich porównania. ==Porównanie może czasami działać ze względu na sposób, w jaki prymitywy JVM działają, ale nie są od niego zależne.

if (num1.equals(num1))
{
 //code
}
Nishan
źródło
1
To (co jest lepsze) lub porównaj wartość zwracaną .longValue().
Giulio Franco
4

Porównywanie innych niż prymitywy (aka Objects) w Javie z ==porównuje ich odwołania zamiast ich wartości. Longjest klasą i dlatego Longwartości są obiektami.

Problem polega na tym, że programiści Javy chcieli, aby ludzie używali Longich tak, jak kiedyś, longaby zapewnić kompatybilność, co doprowadziło do koncepcji autoboxingu, która jest zasadniczo cechą polegającą na tym, że long-wartości zostaną zmienione na Long-Objects i odwrotnie w razie potrzeby. Zachowanie autoboxingu nie jest jednak przez cały czas dokładnie przewidywalne, ponieważ nie jest całkowicie określone.

Aby być bezpiecznym i mieć przewidywalne wyniki, zawsze używaj .equals()do porównywania obiektów i nie polegaj w tym przypadku na autoboxingu:

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }
LionC
źródło