— Якщо розробники могли вигадувати класи, які описують числа, вони вирішили підійти до цієї справи творчо, як справжні розробники.

По-перше, вигадали абстрактний клас Number (число), від якого успадковані типи Byte, Short,Integer, Long, Float, Double. Він має методи, які допомагають перетворювати числа до інших числових типів.

Методи класу Number
1
int intValue()
2
long longValue()
3
float floatValue()
4
double doubleValue()
5
byte byteValue()
6
short shortValue()

— Справді, вже не напишеш:

Long x = 100000;
Integer y = (Integer) x;

— Ага. Типи не примітивні. Тому використовують методи класу Number:

Long x = 100000;
Integer y = x.intValue();

Але тут є ще кілька моментів. Т.к. Integer – це int, то об'єкти такого типу не можна порівнювати класичним знаком «==».

Порівняння примітивних типів
int x = 500;
int y = 500;
x == y; //true
Порівняння непримітивних типів:
Integer x = 500;
Integer y = 500;
x == y; //false
x.equals(y); //true

— Точно. Якось я одразу про це не подумав.

— Але це ще не все.

— Господи, що ж там ще?

— Коли ми присвоюємо змінної типу Integer значення типу int, викликається метод Integer.valueOf:

Код Що відбувається насправді
Integer x = 5;
Integer x = Integer.valueOf(5);

— Ага. Я це зрозумів ще прикладом вище.

— Так ось, функція valueOf не завжди створює новий об'єкт типу Integer.

— Тобто. як це не завжди?

— Вона кешує значення від -128 до 127.

Код Що відбувається насправді Опис
Integer x = 300;
Integer y = 300;
Integer z=300;
Integer x = Integer.valueOf(300);
Integer y = Integer.valueOf(300);
Integer z = Integer.valueOf(300);
Всі змінні x,y,z містять посилання на різні об'єкти
Integer x = 100;
Integer y = 100;
Integer z=100;
Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
Integer z = Integer.valueOf(100);
Всі змінні x,y,z містять посилання на той самий об'єкт.
Integer x = new Integer(10)
Integer y = New Integer(10)
Integer z = 10;
Integer t = 10;
Integer x = new Integer(10)
Integer y = New Integer(10)
Integer z = Integer.valueOf(10);
Integer t = Integer.valueOf(10);
Всі змінні z,t містять посилання на той самий об'єкт.

Тобто. ситуація така:

1) Якщо ми пишемо new Integer(), то гарантовано створюється новий об'єкт.

2) Якщо ми викликаємо Integer.valueOf(), явно або при autoboxing, то цей метод може повернути для нас як новий об'єкт, так і віддати об'єкт з кешу, якщо передане число лежить в діапазоні від -128 до 127.

— А що в цьому такого страшного, якщо метод поверне об'єкт із кешу?

— Да нічого. Просто потрібно знати, що іноді, коли цього не очікуєш, об'єкти можуть бути рівними. Там із рівністю взагалі все складно. Якщо ми порівнюємо примітивний тип і не примітивний, вони порівнюються як примітиви:

Приклад проблеми з порівнянням:
int x = 300;
Integer y = 300;
Integer z = 300;

x==y; //true (порівнюються як примітиви за значенням)
x==z; //true (порівнюються як примітиви за значенням)
y==z; //false (порівнюються за посиланням)
Цей приклад ще цікавіший. Тут вже в дію вступає кеш
int x = 100;
Integer y = 100;
Integer z = 100;

x==y; //true (порівнюються як примітиви за значенням)
x==z; //true (порівнюються як примітиви за значенням)
y==z; //true (порівнюються за посиланням, посилаються на той самий об'єкт)
А тут кеш уже не працює
int x = 100;
Integer y = New Integer (100);
Integer z = 100;

x==y; //true (порівнюються як примітиви за значенням)
x==z; //true (порівнюються як примітиви за значенням)
y==z; //false (порівнюються за посиланням, посилаються на різні об'єкти)

— М-так. І як це все запам'ятати…

— Не треба це запам'ятовувати. Потрібно просто зрозуміти, як це все влаштовано і що відбувається насправді, коли в справу вступає примітивний тип та його непримітивний аналог.

Ще раджу тобі подивитися на методи класу Integer, має досить багато хороших і корисних методів. Ти навіть одним із них часто користувався.

— Ага. Пам'ятаю. Integer.parseInt();