Преобразование типов
Числовые преобразования
Расширяющее преобразование выполняется неявно, если целевой тип способен представить диапазон исходного типа по правилам языка:
int count = 42;
long total = count;
double average = total;Основные направления:
byte → short → int → long → float → double
char → int → long → float → double«Расширяющее» не означает «без потери точности». Например, большое значение long может округлиться при преобразовании к float, потому что у float меньше значащих битов.
Сужающее преобразование требует явного cast:
long source = 3_000_000_000L;
int narrowed = (int) source; // переполнение, исключения не будетCast берёт младшие биты для целых типов или округляет дробное число к нулю при переходе к целому. Java не проверяет потерю диапазона автоматически.
Продвижение в выражениях
byte, short и char в арифметике обычно продвигаются до int:
byte left = 10;
byte right = 20;
// byte sum = left + right; // результат int
int sum = left + right;Составное присваивание включает неявное приведение:
byte value = 120;
value += 10; // эквивалентно value = (byte) (value + 10), получится -126Это удобство может скрыть переполнение.
Ссылочные преобразования
Upcast от наследника к родителю безопасен и неявен:
Object value = "ready";Downcast проверяется во время выполнения:
if (value instanceof String text) {
System.out.println(text.length());
}Явный cast не преобразует объект в другой класс, а лишь утверждает компилятору ожидаемый runtime-тип. Неверное утверждение приводит к ClassCastException.
Boxing, unboxing и generics
Integer boxed = 10;
int primitive = boxed;Unboxing null выбрасывает NullPointerException. Кроме того, generics инвариантны: преобразовать List<Integer> в List<Number> нельзя, хотя отдельный Integer можно присвоить переменной Number.
Строки и числа
int count = Integer.parseInt("42");
long id = Long.parseLong("9000");
double ratio = Double.parseDouble("0.25");
String text = String.valueOf(count);Некорректный формат приводит к NumberFormatException. Для пользовательского ввода нужно заранее определить допустимый формат и обработать ошибку на границе системы.
Точные преобразования
Когда переполнение недопустимо, используйте проверяющие методы:
long value = 2_000_000_000L;
int exact = Math.toIntExact(value);
int sum = Math.addExact(1_500_000_000, 1_000_000_000); // ArithmeticExceptionОни превращают тихое переполнение в явное исключение.
Ловушки
- Считать любой widening conversion точным.
- Ожидать исключение от обычного целочисленного переполнения.
- Думать, что cast изменяет реальный класс объекта.
- Не проверять
nullперед unboxing. - Путать
(int) doubleс математическим округлением: cast отбрасывает дробную часть по направлению к нулю. - Не учитывать продвижение
byte/short/charдоint.
Вопросы на собеседовании
- Чем расширяющее преобразование отличается от сужающего?
- Может ли расширяющее преобразование потерять точность?
- Почему сумма двух
byteимеет типint? - Что делает cast ссылочного типа?
- Чем
(int) 2.9отличается отMath.round(2.9)? - Как обнаружить переполнение при преобразовании
longвint?
Связанные заметки
Переменные и типы данных Java · Классы обертки Java · Работа с числовыми данными · Raw Type · Наследование · Работа с исключениями в Java