Классы обёртки (Wrapper type) Упаковка и распаковка (boxing unboxing)

Я немного запутался, помогите пожалуйста. Вот к примеру код:

Integer n1 = 1;
Integer n2 = 1;
Integer n3 = new Integer(1);
Integer n4 = new Integer(1);

// 1й вывод
System.out.println(n1 == 1); //true
// 2й вывод
System.out.println(n1 == n2); //true
// 3й вывод
System.out.println(n1 == n3); //false
// 4й вывод
System.out.println(n3 == 1); //true
// 5й вывод
System.out.println(n3 == n4); //false

Переменные n1 и n2 содержат в себе адрес указывающий на память в кэше.

Переменные n3 и n4 содержат в себе адрес указывающий на память в куче.

В 1-м выводе, в переменном n1 выполняется unboxing и возвращается значение, то есть сравнения int == int

Во 2-м выводе, сравниваются две ссылки, указывающие на одну и ту же ячейку в кэш памяти, а то есть, сравнения ref == ref

В 3-м выводе, сравниваются адреса с разных мест, n1 память в кэше, n3 память в куче, а то есть ref == ref

В 4-м выводе как и в 1-м, происходит сравнений значений, после того как выполнится unboxing и вместо адреса в переменном n3 появится значения, а то есть int == int

И в 5-м выводе, произайдёт сравнения адресов которые указаны на разные ячейки памяти в куче ref == ref

Правильно ли, я всё понял?


Ответы (1 шт):

Автор решения: Andrey Tabakov

Да, всё верно.

Небольшое дополнение по поводу кэша. Он ограничен, по умолчанию: -128..127.

Это означает

Integer n1 = 127;
Integer n2 = 127;
Integer n3 = 128;
Integer n4 = 128;

// true - ссылка одинаковая из кэша, объект с этим значением был создан заранее, никакую новую память мы не выделили. Взяли готовую ссылку.
System.out.println(n1 == n2); 
// false - ссылки разные, в кэш не попали, сделали 2 объекта.
System.out.println(n3 == n4); 

Его можно расширить через флаги JVM.

-Djava.lang.Integer.IntegerCache.high=512

или

-XX:AutoBoxCacheMax=512

Тогда кэш будет: -128..512.

Забавный факт -128 значение захардкожено. Исправлять не стали.

→ Ссылка