Pytanie w sprawie operator-keyword, integer, wrapper, java, equals – Używanie operatora == w Javie do porównywania obiektów opakowujących

46

Czytam SCJP Java 6 autorstwa Kathy Sierra, a Bert Bates i ta książka bardzo mnie myli. Na stronie 245 podają poniższy kod.

<code>Integer i1 = 1000;
Integer i2 = 1000;
if(i1 != i2)
System.out.println("different objects");

//Prints output
different objects
</code>

Następnie na następnej stronie mają następujący kod

<code>Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4)
System.out.println("same objects");

//Prints output
same objects
</code>

Jestem zmieszany! Kiedy sam to wypróbuję, wydaje się, że nie można użyć == do porównania w taki sam sposób, w jaki używa się metody equals (). Użycie == zawsze daje mi „fałsz”, nawet jeśli zmienne całkowite mają tę samą wartość (tj. 10). Mam rację? Użycie == do porównania tego samego obiektu Integer (z tymi samymi wartościami) zawsze spowoduje „fałsz”

Twoja odpowiedź

8   odpowiedzi
0

Porównanie łańcuchów i porównanie liczb całkowitych przy użyciu == i! = Daje wyniki boolowskie nie tak, jak się tego spodziewamy. Bądź więc ostrożny i upewnij się, że możliwe nieznane wyniki nie utrudniają wydajności, niezawodności i dokładności oprogramowania.

0

„==” zawsze porównuje lokalizację pamięci lub odniesienia do obiektów wartości.. Ale równa się także pośrednio operator „==” do porównywania wartości. Integer używa cache Integer do przechowywania wartości od -128 do + 127. Jeśli operator == jest używany do sprawdzenia jakichkolwiek wartości pomiędzy -128 a 127, to zwraca true. jeśli jakakolwiek wartość pomiędzy -128 do 127 jako

<code>Integer i1 = -128; 
Integer i2 = -128; 
System.out.println(i1 == i2); // returns true
</code>

poza powyższym zakresem zwraca fałsz

<code>Integer i1 = 1000;
Integer i2 = 1000;
System.out.println(i1 == i2); // returns false
</code>

Odnoś link dla dodatkowych informacji

7

żenia, jeśli zrobisz:

<code>Integer i3 = new Integer(10);
Integer i4 = new Integer(10);
</code>

Nie będziesz mieć nowych obiektów, ponieważ stworzysz nowe obiekty. Jeśli napiszesz kod w następujący sposób, zostanie on internowany:

<code>Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);
</code>

Będą teraz ponownie tym samym obiektem. Jeśli przyjrzysz się metodzie valueOf wewnątrz klasy Integer.java w pliku src.zip, możesz zobaczyć, gdzie sprawdza, czy wartość int jest poza -128 do 127, inaczej wywołuje nową klasę Integer ładuje go z pamięci podręcznej.

58

internowanie obiektów. Java praktykuje małe liczby (mniej niż 128), więc wszystkie wystąpieniaInteger(n) zn w internowanym zakresie są takie same. Liczby większe lub równe 128 nie są więc internowaneInteger(1000) obiekty nie są sobie równe.

@JamesScriven java nie internuje Integer dynamicznie, internowane wartości Integer są przydzielane podczas uruchamiania. Sprawdza tylko zakres (wartość <internedValues.length), gdy autoboxing int. josefx
Łał! Właśnie to widziałem. Czemu?? To takie zagmatwane. Jakie jest tego uzasadnienie? dido
Widziałem przypadki, w których internowanie spowodowało poważną degradację wydajności. Tworzyłem wiele liczb całkowitych w wąskiej pętli, a koszt instancji nie był trywialny. James Scriven
@JamesScriven Jak każda technika optymalizacji, ręczne internowanie może się nie udać. Istnieje różnica kosztów między robieniem tego ręcznie do wielu liczb całkowitych w wąskiej pętli, a robieniem tego z wyprzedzeniem do małej liczby liczb całkowitych. dasblinkenlight
2
<code>Integer i1 = 1000;
Integer i2 = 1000;
</code>

Kompilator „pudełka” int 1000 jako obiekt typu Integer. W tym celu konwertuje źródło na następujące:

<code>Integer i1 = Integer.valueOf(1000);
Integer i2 = Integer.valueOf(1000);
</code>

TerazvalueOf może być prostym wezwaniem donew Integer(1000) jednak tworzenie nowego obiektu typu Integer za każdym razemint w pudełku będzie kosztować zarówno czas, jak i przestrzeń. Aby tego uniknąć, klasa Integer przechowuje tablicę obiektów Integer dla ograniczonego zakresu wartości int.

<code>if(value> maxRange || value< minRange){
     //not in pool return new Integer
     return new Integer(value);
}else{
     //return pooled Integer object
     //for the value, pool contains all Integer
     //values from minRange to maxRange
     return integerPool[value-minRange];
}
</code>

Szybkość uzyskaną w porównaniu z utraconą pamięcią można dostosować, ustawiając zakres za pomocą argumentu jvm przy starcie programu (afaik domyślnie -127 do 128).

0

Gdy operator Java == jest używany do porównywania czegokolwiek innego niż typy pierwotne, sprawdza równość referencyjną; ma to zastosowanie nawet wtedy, gdy porównywane rzeczy są owinięte w prymitywy. DalejvalueOf metoda autoboxing generowana przez metodę i kompilator może generalnie swobodnie zwracać nowy obiekt, który nie będzie równy żadnemu innemu wcześniej istniejącemu odwołaniu, lub zwrócić odniesienie do istniejącego obiektu (co oczywiście byłoby odniesieniem- równy dowolnemu istniejącemu wcześniej odniesieniu identyfikującemu ten sam obiekt). Wdrożenia są wymagane do utrzymania „puli”Integer instancje dla wartości -128 do 127, takie jak wszystkie wywołaniaInteger.valueOf na każdym określonym numerze w tym zakresie zwróci odniesienia do tego samego obiektu, ale poza tym implementacja będzie mogła zrobić coś takiego

<code>static Integer [] intPool = new Integer[256];

public Integer valueOf(int n)
{
  int hash = (n*0x18675309) >>> 24;
  Integer instance = intPool[n];
  if (instance == null && instance.value != n)
  {
    instance = new Integer(n);
    intPool[hash] = instance ;
  }
  return instance;
}
</code>

Nie oczekuję, że implementacje Java zrobią coś takiego, ponieważ w wielu przypadkach współczynnik trafień w pamięci podręcznej może być bliski 0%, a dodatkowy czas spędzony na szukaniu instancji w pamięci podręcznej zostałby zmarnowany. Niemniej jednak nigdy nie ma gwarancji, że odniesienie zwrócone przezinstanceOf nie pasuje do jakiegoś poprzedniego odwołania zwróconego przez tę metodę (nawet jeśli nie pasuje doostatni, ubiegły, zeszły odwołanie zwrócone przez tę metodę, niektóre algorytmy buforowania mogą spowodować zwróceniewcześniej odniesienie, zwłaszcza jeśli pula jest współdzielona przez wiele wątków bez blokowania. Brak blokady nigdy nie spowoduje, że kod zwróci cokolwiek innego niż odniesienie do liczby całkowitej o poprawnej wartości, ale może spowodować nieprzewidywalne odmiany, w których zwrócone referencje są porównywalne). Tylko odniesienie doInteger obiekty utworzone bezpośrednio za pomocą konstruktoranew Integer(n) gwarantowane są wyjątkowe; kod, który oczekuje na każde odwołanie zwrócone przezvalueOf aby nie pasować do żadnego odwołania zwróconego przezvalueOf, nie zauważając, że się nie zgadza, należy uznać za złamane.

17

Integer zobaczysz toInteger.valueOf(int) totalizator piłkarski wszystkie wartości -128 do 127. Powodem jest to, że małe wartości liczb całkowitych są często używane i dlatego są warte łączenia / buforowania.

Z prosto zInteger.java:

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

Należy zauważyć, że ta pula jest specyficzna dla implementacji i nie ma gwarancji zakresu puli.

Odpowiedzi na temat internowania są poprawne, ale niepoprawne z terminologią. Internowanie w Javie zwykle oznacza, że ​​środowisko Java wykonuje pulowanie (takie jak String's intern). W przypadku Integera sama klasa wykonuje pulę. Nie ma w tym żadnej magii JVM.

Właściwie to buforowanieInteger obiekty dlaint wartości w zakresie [-128, 127] są określone wdokumentacja API, więc ta część zakresu jest w rzeczywistości gwarantowana. Ted Hopp
0

Wedługjls-5.1.7

<code>If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f,   
or an int or short number between -128 and 127 (inclusive), then let r1 and r2 
be the results of any two boxing conversions of p. It is always the case that r1 == r2.
</code>

Tak, każda liczba między-128 i127 jest buforowany przez klasę Interger.
Pamiętaj, że porównując dwa obiekty zawsze używajequals metoda.

Kod buforowania jest zapisanyIntegerCache klasa, która jest członkiemInteger klasa.

Oto fragment kodu:

<code> /**
 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

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

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}
</code>
Referencjejls-5.1.7Kod klasy całkowitejInteger Java doc

Powiązane pytania