2009-11-09 11 views
120
class D { 
    public static void main(String args[]) { 
     Integer b2=128; 
     Integer b3=128; 
     System.out.println(b2==b3); 
    } 
} 

wyjściowa:Dlaczego 128 == 128 zwraca wartość false, ale 127 == 127 zwraca wartość true podczas konwersji na opakowania całkowite?

false 

class D { 
    public static void main(String args[]) { 
     Integer b2=127; 
     Integer b3=127; 
     System.out.println(b2==b3); 
    } 
} 

wyjściowa:

true 

Uwaga: Liczby pomiędzy -128 i 127 są prawdziwe.

+10

Można znaleźć http://bexhuff.com/2006/11/java-1-5-autoboxing-wackyness pouczające. –

+1

jak doszło do tego, aby zadać to pytanie? to jest naprawdę zabawne, ale nigdy nie natrafiamy na coś takiego "w prawdziwym świecie" ... lub? –

+0

http://stackoverflow.com/a/11882284/57695 –

Odpowiedz

167

Podczas kompilowania numer dosłowne w Javie i przypisać go do Integer (kapitału I) kompilator emituje:

Integer b2 =Integer.valueOf(127) 

Ta linia kodu jest również generowany podczas korzystania autoboxing.

valueOf jest realizowana w taki sposób, że niektóre numery są „łączone” i zwraca tę samą instancję do wartości mniejszej niż 128.

z kodu źródłowego Java 1.6, linia 621:

public static Integer valueOf(int i) { 
    if(i >= -128 && i <= IntegerCache.high) 
     return IntegerCache.cache[i + 128]; 
    else 
     return new Integer(i); 
} 

Wartość high może zostać skonfigurowana do innej wartości z właściwością systemową.

-Djava.lang.Integer.IntegerCache.high = 999

Jeśli uruchomić program z tej właściwości systemu, to będzie prawdziwa moc!

Oczywisty wniosek: nigdy nie należy polegać na identycznych dwóch referencjach, zawsze należy je porównywać z metodą .equals().

Tak więc b2.equals(b3) wyświetli wartość true dla wszystkich logicznie równych wartości b2, b3.

Należy pamiętać, że pamięć podręczna Integer nie występuje ze względów wydajnościowych, ale raczej z powodu zgodności z JLS, section 5.1.7; tożsamość obiektu musi być podana dla wartości od -128 do 127 włącznie.

Integer#valueOf(int) dokumentuje również ten problem:

ta metoda jest prawdopodobne, uzyskując znacznie lepszą wydajność czasie i przestrzeni poprzez buforowanie często żądane wartości. Ta metoda zawsze będzie buforować wartości w zakresie od -128 do 127 włącznie i może buforować inne wartości poza tym zakresem.

+1

Zwróć uwagę, że wartości mniejsze niż 127 będą ignorowane przez java, a wartości większe niż Integer.MAX_VALUE-128 będą ograniczone. –

+0

Liczby całkowite są buforowane dla wartości bajtów w Java 5 i wyższych, tworząc nową liczbę całkowitą (1) == nową liczbę całkowitą (1). Nie dotyczy to jednak środowiska Java w wersji 1.4 lub niższej, więc należy zachować ostrożność, jeśli konieczne jest wcześniejsze przejście na to środowisko. – MetroidFan2002

+10

nie, to jest złe. new Integer (1) == new Integer (1) ma wartość false bez względu na jvm. AFAIK żaden kompilator nie oszuka na "nowym" słowie kluczowym. MUSI zawsze tworzyć nowy obiekt. –

19

Autoboxing cache -128 do 127. Jest to określone w JLS (5.1.7).

Jeżeli wartość p są 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 są wynikami dowolnych dwóch konwersji bokserskich z. Zawsze jest tak, że r1 == r2.

Prosta zasada, aby pamiętać, gdy mamy do czynienia z obiektami jest - stosowanie .equals jeśli chcesz sprawdzić, czy dwa obiekty są „równe”, użycie == gdy chcesz sprawdzić, czy wskazują one na tej samej instancji .

8

Korzystanie prymitywne typy danych, ints, by produkować prawdziwe w obu przypadkach oczekiwany wynik.

Ponieważ jednak używasz obiektów Integer, operator == ma inne znaczenie.

W kontekście obiektów, == sprawdza, czy zmienne odnoszą się do tego samego odniesienia do obiektu.

Aby porównać wartości obiektów, należy użyć metody equals() E.g.

b2.equals(b1) 

który wskaże czy b2 jest mniejsza niż b1, większe lub równe (sprawdź szczegóły API)

-4

napisałem następujący jak ten problem jest nie tylko specyficzne Integer. Mój wniosek jest taki, że najczęściej, jeśli używasz API nieprawidłowo, zobaczysz nieprawidłowe zachowanie. Używać go poprawnie i powinieneś zobaczyć poprawne zachowanie:

public static void main (String[] args) { 
    Byte b1=127; 
    Byte b2=127; 

    Short s1=127; //incorrect should use Byte 
    Short s2=127; //incorrect should use Byte 
    Short s3=128; 
    Short s4=128; 

    Integer i1=127; //incorrect should use Byte 
    Integer i2=127; //incorrect should use Byte 
    Integer i3=128; 
    Integer i4=128; 

    Integer i5=32767; //incorrect should use Short 
    Integer i6=32767; //incorrect should use Short 

    Long l1=127L;   //incorrect should use Byte 
    Long l2=127L;   //incorrect should use Byte 
    Long l3=13267L;   //incorrect should use Short 
    Long l4=32767L;   //incorrect should use Short 
    Long l5=2147483647L; //incorrect should use Integer 
    Long l6=2147483647L; //incorrect should use Integer 
    Long l7=2147483648L; 
    Long l8=2147483648L; 

    System.out.print(b1==b2); //true (incorrect) Used API correctly 
    System.out.print(s1==s2); //true (incorrect) Used API incorrectly 
    System.out.print(i1==i2); //true (incorrect) Used API incorrectly 
    System.out.print(l1==l2); //true (incorrect) Used API incorrectly 

    System.out.print(s3==s4); //false (correct) Used API correctly 
    System.out.print(i3==i4); //false (correct) Used API correctly 
    System.out.print(i5==i6); //false (correct) Used API correctly 
    System.out.print(l3==l4); //false (correct) Used API correctly 
    System.out.print(l7==l8); //false (correct) Used API correctly 
    System.out.print(l5==l6); //false (correct) Used API incorrectly 

} 
2

spojrzeć na Integer.java, jeżeli wartość wynosi od -128 do 127, będzie korzystał z pamięci podręcznej basen, więc (Integer) 1 == (Integer) 1 podczas (Integer) 222 != (Integer) 222

/** 
* Returns an {@code Integer} instance representing the specified 
* {@code int} value. If a new {@code Integer} instance is not 
* required, this method should generally be used in preference to 
* the constructor {@link #Integer(int)}, as this method is likely 
* to yield significantly better space and time performance by 
* caching frequently requested values. 
* 
* This method will always cache values in the range -128 to 127, 
* inclusive, and may cache other values outside of this range. 
* 
* @param i an {@code int} value. 
* @return an {@code Integer} instance representing {@code i}. 
* @since 1.5 
*/ 
public static Integer valueOf(int i) { 
    assert IntegerCache.high >= 127; 
    if (i >= IntegerCache.low && i <= IntegerCache.high) 
     return IntegerCache.cache[i + (-IntegerCache.low)]; 
    return new Integer(i); 
}  
4

Jest to optymalizacja pamięci w języku Java.

Aby zapisać w pamięci, wszystkie obiekty wrapper Java sposoby ponownego wykorzystania ", których wartości spadek w następujących zakresach:

Wszystkie wartości logiczne (prawda i fałsz)

Wszystko Byte wartości

Wszystkie wartości znaków od \ u0000 do \ u007f (tj. 0 do 127 w systemie dziesiętnym)

Wszystkie wartości krótkie i całkowite od -128 do 127.

Uwaga:

  • jeśli tworzyć logiczną z nowych Boolean (wartość); zawsze otrzymasz nowy obiekt

  • jeśli utworzysz String z nowym ciągiem (wartość); zawsze otrzymasz nowy obiekt

  • jeśli utworzysz Integer z nową liczbą całkowitą (wartość); zawsze możesz liczyć nowy obiekt

itp

Powiązane problemy