2013-02-22 20 views
23

Dlaczego Integer "=" operator nie działa dla wartości 128 i po wartościach całkowitych? Czy ktoś może wyjaśnić tę sytuację?Dlaczego operator równości działa dla wartości całkowitych do liczby 128?

To jest moje środowisko Java: wersja java "1.6.0_37"

Java (TM) SE Runtime Environment (build 1.6.0_37-b06)

Java HotSpot (TM) 64- bit Server VM (build 20.12-B01, tryb mieszany) kod

próbki:

Integer a; 
    Integer b; 
    a = 129; 
    b = 129; 

    for (int i = 0; i < 200; i++) { 
     a = i; 
     b = i; 

     if (a != b) { 
      System.out.println("Value:"+ i + " - Different values"); 
     } else { 
      System.out.println("Value"+ i + " Same values"); 
     } 
    } 

Część wyjścia konsoli:

Value:124 - Same values 
Value:125 - Same values 
Value:126 - Same values 
Value:127 - Same values 
Value:128 - Different values 
Value:129 - Different values 
Value:130 - Different values 
Value:131 - Different values 
Value:132 - Different values 

Dzięki!

+0

od -128 do 127 –

+0

'=' jest operatorem przypisania i nie używa się go w aktualnym przykładowym kodzie; miałeś na myśli '=='? – geoffspear

Odpowiedz

19

Sprawdź the source code of Integer. Możesz zobaczyć tam bufor wartości.

Buforowanie dzieje się tylko wtedy, gdy używasz Integer.valueOf(int), a nie, jeśli używasz new Integer(int). Autoboxing używany przez ciebie wykorzystuje Integer.valueOf

Według JLS, zawsze można liczyć na to, że dla wartości między -128 i 127, masz identyczne obiekty Integer po autoboxing, a na niektórych implementacjach można dostać identyczne obiekty nawet dla wyższych wartości.

Właściwie w Javie 7 (i myślę, że w nowszych wersjach Java 6) zmieniono implementation klasy IntegerCache, a górna granica nie jest już na stałe zakodowana, ale można ją konfigurować za pośrednictwem właściwości "java.lang. Integer.IntegerCache.high ", więc jeśli uruchomisz program z parametrem VM -Djava.lang.Integer.IntegerCache.high=1000, otrzymasz" Te same wartości "dla wszystkich wartości.

Ale JLS nadal gwarantuje mu tylko aż 127:

Idealnie, boks daną pierwotną wartość p, zawsze uzyskując identyczną nazwę. W praktyce może to nie być możliwe przy użyciu istniejących technik implementacji. Powyższe zasady są pragmatycznym kompromisem. Ostatnia klauzula powyżej wymaga, aby pewne wspólne wartości zawsze były zapakowane w nieodróżnialne obiekty. Implementacja może je buforować, leniwie lub niecierpliwie.

W przypadku innych wartości, sformułowanie to nie akceptuje żadnych założeń dotyczących tożsamości pudełkowych wartości w części programatora. Umożliwiłoby to (ale nie wymagało) współużytkowanie niektórych lub wszystkich tych odniesień.

Zapewnia to, że w większości przypadków zachowanie będzie pożądane, bez nakładania nadmiernej kary za wydajność, zwłaszcza na małych urządzeniach. Implementacje o mniejszej ilości pamięci mogą na przykład buforować wszystkie znaki i skróty, a także liczby całkowite i długie w zakresie -32K - + 32K.

+0

+1 Byłoby świetnie, gdyby połączyć kod źródłowy z odpowiedzią :) – PermGenError

6

Według języka Java Specyfikacje:

Jeśli wartość p jest zapakowane jest prawdziwe, fałszywe, bajt, char w zakresie \ u0000 do \ u007f lub int lub krótki numer między - 128 i 127, a następnie niech r1 i r2 będą wynikami dowolnych dwóch konwersji bokserskich p. Zawsze jest tak, że r1 == r2.

JLS Boxing Conversions

Refer to this article for more information on int caching

+5

Ta odpowiedź jest błędna, nie ma nic wspólnego z jvm hotspot, buforowanie jest zaimplementowane w kodzie źródłowym Integer, – lbalazscs

+1

@lbalazscs, o ile wiem, że wartości, które są buforowane zależą od jvm. Myślę, że to buforowanie jest określone w specyfikacji języka Java, ale wartości, które mają być buforowane, nie są określone. Właśnie dlatego wspomniałem o hotspot jvm. Czy to nie jest poprawne? –

+3

To nie jest poprawne. Dlaczego nie spojrzysz na kod źródłowy 'java.lang.Integer', na przykład. –

2

Zastosowanie .equals() zamiast ==.

Wartości całkowite są buforowane tylko dla liczb od -127 do 128, ponieważ są najczęściej używane.

if (a.equals(b)) { ... } 
6

Integer to klasa opakowania dla int.

Integer != Integer porównuje rzeczywiste odniesienie do obiektu, gdzie int != int porówna wartości.

Jak już podano, wartości od -128 do 127 są buforowane, więc te same obiekty są zwracane dla nich.

Jeśli poza tym zakresem, zostaną utworzone oddzielne obiekty, więc odniesienie będzie inne.

Aby to naprawić:

  • Bądź typy int lub
  • Obsada typy do int lub
  • Korzystając .equals()
3

Przedmiotem Integer posiada wewnętrzny mechanizm cache:

private static class IntegerCache { 
    static final int high; 
    static final Integer cache[]; 

    static { 
     final int low = -128; 

     // high value may be configured by property 
     int h = 127; 
     if (integerCacheHighPropValue != null) { 
      // Use Long.decode here to avoid invoking methods that 
      // require Integer's autoboxing cache to be initialized 
      int i = Long.decode(integerCacheHighPropValue).intValue(); 
      i = Math.max(i, 127); 
      // Maximum array size is Integer.MAX_VALUE 
      h = Math.min(i, Integer.MAX_VALUE - -low); 
     } 
     high = h; 

     cache = new Integer[(high - low) + 1]; 
     int j = low; 
     for(int k = 0; k < cache.length; k++) 
      cache[k] = new Integer(j++); 
    } 

    private IntegerCache() {} 
} 

zobaczyć również metodę valueOf:

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

Dlatego należy użyć valueOf zamiast new Integer. Autoboxing używa tej pamięci podręcznej.

zobaczyć również ten wpis: https://effective-java.com/2010/01/java-performance-tuning-with-maximizing-integer-valueofint/

Korzystanie == nie jest dobrym pomysłem, korzystanie równa porównać wartości.

1

W zależności od tego, jak masz swoje instancje Integer, nie może pracować dla każdej wartości:

System.out.println(new Integer(1) == new Integer(1)); 

drukuje

false 

To dlatego, że operator == stosowane odwołać wpisany argumentów nie ma nic zrobić z wartością, którą reprezentują te operandy.