Целочисленное кэширование в Java с новым оператором

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

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

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

Если есть новый объект, тогда как 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

объяснение

Когда вы сравниваете 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(int), так как этот метод может принести значительно лучшее пространство и время производительность за счет кэширования часто запрашиваемых значений. Этот метод всегда -128 значения в диапазоне от -128 до 127 включительно и может кэшировать другие значения за пределами этого диапазона.

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

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).

Ответ 2

Вы сравниваете ссылки, когда используете ==, поэтому результаты будут непредсказуемыми. Для любого ссылочного типа в Java вы должны использовать метод equals.

Ответ 3

То, что вы сравниваете, - это System.identityHash() для объектов. Die примитивный тип int вместо того, чтобы сравнивать правильно Целое число - это объект-оболочка. Объект всегда сравнивается с методом equals. Поскольку Integer - это особый тип, его можно сравнить с примитивом int.

Итак, в основном то, что вы делаете:

System.out.println(b==c);                                                 //true
System.out.println(System.identityHash(a)==System.identityHash(b));       //false
System.out.println(a==c);                                                 //true

Таким образом, a==b является false в этом случае, потому что это 2 разных объекта на 2 разных адресах памяти.

Используйте метод equals, как если бы вы сравнивали String