— Раз уж разработчики могли придумывать классы, которые описывают числа, они решили подойти к этому делу творчески, как настоящие разработчики.

Во-первых, придумали абстрактный класс 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();