Целочисленное кэширование в Java с новым оператором - PullRequest
23 голосов
/ 07 мая 2019

В приведенном ниже классе я попытался сравнить класс-оболочку с примитивом, но результаты отличаются.

Я проверил следующие ссылки ссылки :

Более интересный вопрос: почему new Object(); требуется для создания уникального экземпляра каждый раз?то есть почему new Object(); не разрешено кэшировать?Ответ - звонки wait(...) и notify(...).Кэширование новых Object() s приведет к неправильной синхронизации потоков друг с другом, если они не должны.

Если существует новый объект, то как равны a и c?

Если b равно c и c равно a, то a должно быть равно b.Но в следующем случае я получил a != c.

Пожалуйста, объясните.

class WrapperCompare {

    public static void main (String args[]) {
        Integer a = new Integer(10);    
        Integer b = 10; 
        int c=10;
        System.out.println(b==c);       //true
        System.out.println(a==b);       //false
        System.out.println(a==c);       //true
    }
}

Обновление: перейдя по этой ссылке Целочисленное кеширование .

По существу, класс Integer хранит кэш экземпляров Integer в диапазоне от -128 до 127, и все автобокс, литералы и использования Integer.valueOf () будут возвращать экземпляры из этого кэша длядиапазон, который он охватывает.

Так что в этом случае все утверждения должны быть истинными.

1 Ответ

27 голосов
/ 07 мая 2019

Объяснение

При сравнении Integer против int с == необходимо преобразовать Integer в int. Это называется распаковка .

См. JLS§5.1.8 :

Если r является ссылкой типа Integer, то преобразование без распаковки преобразует r в r.intValue()

В этот момент вы сравниваете int с int. А у примитивов нет понятия экземпляров, все они ссылаются на одинаковое значение . Таким образом, результат true.

То есть фактический код, который у вас есть,

a.intValue() == c

приводит к сравнению 10 == 10, оба значения int, больше нет Integer экземпляров.

Вы можете видеть, что new Integer(...) действительно создает новые экземпляры, когда вы сравниваете Integer против Integer. Вы сделали это в a == b.


Примечание

Конструктор new Integer(...) устарел . Вместо этого вы должны использовать Integer#valueOf, он потенциально быстрее и также использует внутренний кеш. Из документации :

Возвращает экземпляр Integer, представляющий указанное значение int. Если новый экземпляр Integer не требуется, этот метод обычно следует использовать в предпочтении перед конструктором Integer(int), поскольку этот метод может дать значительно лучшее пространство и время производительность кеширование часто запрашиваемые значения. Этот метод всегда будет кэшировать значения в диапазоне от -128 до 127 включительно, а может кэшировать другие значения вне этого диапазона.

Кэширование важно отметить здесь, так как оно дает == снова значение true (для кэшированных значений):

Integer first = Integer.valueOf(10);
Integer second = Integer.valueOf(10);
System.out.println(first == second); // true

Кэширование гарантировано для значений от -128 до +127, но может использоваться и для других.

Также обратите внимание, что ваш b фактически выходит из кеша, так как

Integer b = 10;
// same as
Integer b = Integer.valueOf(10);
// and not
Integer b = new Integer(10);

Итак бокс проходит через Integer кеш (см. JLS§5.1.7 ).

...