Dziwny Boks liczbowy w Javie

Właśnie widziałem kod podobny do tego:

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a == b);

        Integer c = 100, d = 100;
        System.out.println(c == d);
    }
}

Po uruchomieniu ten blok kodu zostanie wydrukowany:

false
true

Rozumiem, dlaczego pierwszy jest false: ponieważ dwa obiekty są oddzielnymi obiektami, więc == porównuje odniesienia. Ale nie mogę zrozumieć, dlaczego druga wypowiedź powraca true? Czy istnieje jakaś dziwna zasada autoboxingu, która działa, gdy wartość liczby całkowitej jest w pewnym zakresie? Co tu się dzieje?

Author: Tom, 2010-06-28

9 answers

Linia true jest faktycznie gwarantowana przez specyfikację języka. Z sekcji 5.1.7:

Jeśli wartość p jest true, false, bajt, znak w zakresie \u0000 do \u007f, lub int lub short liczby od -128 do 127, następnie niech r1 i r2 są wynikami dwóch dowolnych Boks konwersje P. To jest zawsze przypadku, że r1 == r2.

Dyskusja toczy się dalej, sugerując, że chociaż druga linia wyjścia jest gwarantowana, pierwsza isn ' t (Zobacz ostatni akapit cytowany poniżej):

Idealnie, Boks danego prymitywu wartość p, zawsze daje identyczne odniesienie. W praktyce to może nie być wykonalne przy użyciu istniejących techniki implementacji. Zasady powyższe są pragmatycznym kompromisem. Na ostatnia klauzula powyżej wymaga, aby pewne wspólne wartości zawsze są boksowane w nierozróżnialne przedmioty. Na implementacja może buforować te, leniwie albo chętnie.

Dla innych wartości, to preparat odrzuca wszelkie założenia dotyczące identity of the boxed values on the część programisty. Pozwoli to na (ale nie wymagają) udostępniania niektórych lub wszystkie te odniesienia.

Gwarantuje to, że w najczęściej przypadki, zachowanie będzie pożądany, bez narzucania zbędnego kary za wykonanie, zwłaszcza na małe urządzenia. Mniej pamięci-ograniczona implementacje mogą na przykład, buforuj wszystkie znaki i szorty, jako oraz liczby całkowite i długie w na zakres-32K - + 32K.

 90
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-09 17:11:09
public class Scratch
{
   public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;  //1
        System.out.println(a == b);

        Integer c = 100, d = 100;  //2
        System.out.println(c == d);
   }
}

Wyjście:

false
true

Tak pierwsze wyjście jest produkowane dla porównania odniesienia; ' a 'i' b ' - są to dwa różne odniesienia. W punkcie 1, w rzeczywistości tworzone są dwa odwołania, które są podobne jak -

Integer a = new Integer(1000);
Integer b = new Integer(1000);

Drugie wyjście jest produkowane, ponieważ JVM próbuje zapisać pamięć, gdy Integer mieści się w zakresie (od -128 do 127). W punkcie 2 nie tworzy się nowego odniesienia typu Integer dla "d". Zamiast tworzenia nowego obiektu dla referencji typu Integer zmienna "d", jest przypisana tylko do wcześniej utworzonego obiektu, do którego odwołuje się "c". Wszystkie są wykonywane przez JVM.

Te reguły zapisywania pamięci są nie tylko dla liczby całkowitej. w celu zachowania pamięci, dwie instancje następujących obiektów wrappera (podczas tworzenia przez Boks) zawsze będą ==, gdzie ich prymitywne wartości są takie same -

  • Boolean
  • Bajt
  • znak od \u0000 do \u007f (7F to 127 w układzie dziesiętnym)
  • krótkie i całkowite od -128 do 127
 23
Author: Razib,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-24 04:03:24

Obiekty całkowite w pewnym zakresie (myślę, że może od -128 do 127) są buforowane i ponownie używane. Liczby całkowite spoza tego zakresu otrzymują za każdym razem nowy obiekt.

 8
Author: Adam Crume,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-28 05:46:17

Tak, istnieje dziwna zasada autoboxingu, która działa, gdy wartości są w pewnym zakresie. Gdy przypisujesz stałą do zmiennej obiektowej, nic w definicji języka nie mówi, że nowy obiekt musi zostać utworzony. Może ponownie użyć istniejącego obiektu z pamięci podręcznej.

W rzeczywistości JVM Zwykle przechowuje w tym celu bufor małych liczb całkowitych, a także wartości takie jak Boolean.TRUE I Boolean.Fałsz.

 4
Author: Avi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-28 05:46:54

To interesująca Uwaga. W książce Effective Java sugeruje zawsze nadpisywanie równości dla własnych klas. Ponadto, aby sprawdzić równość dla dwóch instancji klasy java, zawsze należy użyć metody equals.

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a.equals(b));

        Integer c = 100, d = 100;
        System.out.println(c.equals(d));
    }
}

Zwraca:

true
true
 4
Author: AmirHd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-17 14:13:02

Domyślam się, że Java przechowuje bufor małych liczb całkowitych, które są już "pudełkowe", ponieważ są bardzo powszechne i oszczędza dużo czasu Na ponowne użycie istniejącego obiektu niż na utworzenie nowego.

 3
Author: Omnifarious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-28 05:46:26

W Javie Boks działa w zakresie od -128 do 127 Dla liczby całkowitej. Gdy używasz liczb z tego zakresu, możesz porównać je z operatorem==. Dla obiektów Integer spoza zakresu należy użyć equals.

 3
Author: marvin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-28 06:19:41

W Javie 5 wprowadzono nową funkcję zapisywania pamięci i poprawy wydajności obsługi obiektów typu Integer. Obiekty Integer są buforowane wewnętrznie i ponownie używane przez te same obiekty odniesienia.

  1. Dotyczy to wartości całkowitych w zakresie od -127 do +127 (Maksymalna liczba całkowita).

  2. To buforowanie całkowite działa tylko na autoboxingu. Obiekty Integer będą nie będą buforowane, gdy są budowane przy użyciu konstruktora.

Więcej szczegóły pls przejść poniżej Link:

Integer Cache in Detail

 0
Author: Rahul Maurya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-02 14:15:48

Jeśli sprawdzimy kod źródłowy Integer obeject, znajdziemy źródło metody valueOf w następujący sposób:

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

, które mogą wyjaśnić, dlaczego Integer obiekty, które w zakresie od -128 (Integer.low) do 127 (Integer.high), są tymi samymi obiektami odniesienia podczas autoboxingu. I widzimy, że klasa IntegerCache zajmuje się tablicą pamięci podręcznej Integer, która jest prywatną statyczną klasą wewnętrzną klasy Integer.

Jest inny ciekawy przykład, który może nam pomóc zrozumieć ten dziwny sytuacja:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

      Class cache = Integer.class.getDeclaredClasses()[0]; 
      Field myCache = cache.getDeclaredField("cache"); 
      myCache.setAccessible(true);

      Integer[] newCache = (Integer[]) myCache.get(cache); 
      newCache[132] = newCache[133]; 

      Integer a = 2;
      Integer b = a + a;
      System.out.printf("%d + %d = %d", a, a, b); //The output is: 2 + 2 = 5    

}
 0
Author: L Joey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-17 06:18:08