2013-02-25 8 views
9

Ktoś postulował w wątku na forum, że wiele osób, a nawet doświadczonych programistów Java, nie zrozumie następującego spokoju kodu Java.Poufne zachowanie == po postinrementacji

Integer i1 = 127; 
Integer i2 = 127; 
System.out.println(i1++ == i2++); 
System.out.println(i1 == i2); 

Jako osoba, która interesuje się Javą, podzieliłem się z nią swoimi przemyśleniami i osiągnąłem następujący rezultat.

System.out.println(i1++ == i2++); 
// True, since we first check for equality and increment both variables afterwards. 

System.out.println(i1 == i2); 
// True again, since both variables are already incremented and have the value 128 

Eclipse mówi inaczej. Pierwsza linia jest prawdziwa, a druga jest fałszywa.

Naprawdę doceniam wyjaśnienie.

Drugie pytanie. Czy ta Java jest specyficzna, czy też ten przykład może się utrzymywać na przykład w językach opartych na C?

+0

try 'i1.equals (I2)' – vikingsteve

+8

http://stackoverflow.com/questions/5117132/integer-wrapper-objects-share-the-same-instances-only-within-the-value-127 –

+0

ten Pytanie jest bardzo podobne do tego opublikowanego przez @DominikKunicki –

Odpowiedz

14
Integer i1 = 127; 
Integer i2 = 127; 
System.out.println(i1++ == i2++); 
// here i1 and i2 are still 127 as you expected thus true 
System.out.println(i1 == i2); 
// here i1 and i2 are 128 which are equal but not cached 
    (caching range is -128 to 127), 

W przypadku 2, jeśli używasz equals() że to return true jako == operatora dla liczb działa tylko dla pamięci podręcznej wartości. jako 128 jest poza zakresem cache wartości powyżej 128 nie będą buforowane, co youhave używać equals() sposób sprawdzić, czy dwa przypadki całkowitych powyżej 127 są prawdziwą

Test:

Integer i1 = 126; 
    Integer i2 = 126; 
    System.out.println(i1++ == i2++);// true 
    System.out.println(i1 == i2); //true 



Integer i1 = 126; 
     Integer i2 = 126; 
     System.out.println(i1++ == i2++);// true 
     System.out.println(i1.equals(i2)); //true 

    Integer i1 = 128; 
     Integer i2 = 128; 
     System.out.println(i1++ == i2++);// false 
     System.out.println(i1==i2); //false 

    Integer i1 = 128; 
     Integer i2 = 128; 
     System.out.println(i1++.equals(i2++));// true 
     System.out.println(i1.equals(i2)); //true 
+4

Jako uwaga, uważam, że zakres buforowania jest specyficzny dla implementacji JVM i nie jest częścią JLS. Dlatego nie można zagwarantować, że to zachowanie będzie spójne w maszynach JVM. –

+1

@ChrisKnight Nie jest to zależne od implementacji, ponieważ znajduje się w specyfikacji. [Ustęp 5.1.7] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7) stwierdza: * "Jeśli wartość p jest w ramce, to [...] int lub krótka liczba od -128 do 127 (włącznie), następnie niech r1 i r2 będą wynikami dowolnych dwóch konwersji boksu p. Zawsze jest tak, że r1 == r2. "* –

+1

@ Mattias Buelens - Obaj mamy rację.Aby to wyjaśnić, gwarantowane jest od -128 do 127 (włącznie). Jednak JVM mogą rozszerzyć ten buforowany zakres. Dalszy tekst w twoim odnośniku: "Implementacje o mniejszej ilości pamięci mogą na przykład buforować wszystkie wartości char i short, a także wartości int i long w zakresie od -32K do + 32K.". –

1

As wyjaśniono, że jest to spowodowane Integer caching. Dla zabawy, można uruchomić program z poniższej opcji JVM:

-XX:AutoBoxCacheMax=128 

i będzie drukować prawda dwukrotnie (opcja dostępna na hostpot 7 - niekoniecznie na innych JVMs).

zauważyć, że:

  • to JVM specyficzny
  • zmodyfikowany zachowanie jest zgodne z JLS, który mówi, że wszystkie wartości między -128 a +127 musi być buforowane, ale także mówi, że inne wartości may Być buforowane.

Konkluzja: druga instrukcja print jest niezdefiniowane w Javie i może drukować prawda lub fałsz w zależności od implementacji JVM i/lub opcji JVM używany.

+0

Po prostu uruchomiłem go z tym parametrem - i wciąż mam Fałsz. –

+0

@AleksG Działa z hotspotem w wersji 7u11. – assylias

+0

Z OpenJDK na 64-bitowym systemie Linux tak się nie dzieje. –

Powiązane problemy