Приведение типов в Java
Преобразование примитивных типов в Java: неявное расширение и явное сужение, типичные ошибки и способы их избежать.
Приведение типов — это преобразование значения из одного типа в другой. В Java оно бывает двух видов: расширяющее преобразование, которое происходит автоматически и никогда не теряет данные, и сужающее преобразование, которое требует явного приведения и может привести к потере данных.
Расширяющее (неявное) преобразование
Расширяющее преобразование перемещает значение в тип большего размера. Компилятор выполняет его автоматически — никакого специального синтаксиса не нужно:
int i = 100;
long l = i; // int → long (widening)
double d = l; // long → double (widening)
System.out.println(i); // 100
System.out.println(l); // 100
System.out.println(d); // 100.0Стандартный порядок расширяющих преобразований:
byte → short → int → long → float → double
char ↗(char расширяется до int и далее, но не до short или byte.)
Расширяющее преобразование никогда не теряет диапазон — long всегда помещается в диапазон double, даже если double не может точно представить каждое значение long. Следите за этим пробелом в точном представлении при экстремальных значениях.
Сужающее (явное) приведение
Сужающее преобразование перемещает значение в тип меньшего размера. Java отказывается делать это неявно, поскольку данные могут быть потеряны. Вы должны явно указать это с помощью (targetType):
double d = 9.99;
int i = (int) d; // explicit narrowing cast
System.out.println(i); // 9 — the fractional part is droppedПриведение отсекает дробную часть в сторону нуля — оно не выполняет округление.
Для целых чисел приведение сохраняет только младшие биты:
int big = 130;
byte b = (byte) big;
System.out.println(b); // -126 — overflow wraps aroundbyte занимает 8 бит, диапазон -128…127. Биты числа 130 (10000010) в дополнительном коде интерпретируются как -126.
Распространённый случай: целочисленное деление с получением вещественного числа
Чистая целочисленная арифметика использует целочисленное деление — 5 / 2 == 2, а не 2.5. Чтобы получить вещественный результат, приведите хотя бы один операнд перед делением:
int total = 5;
int count = 2;
double avgWrong = total / count; // 2.0 — division is still integer
double avgRight = (double) total / count; // 2.5 — total widened firstЭто самая распространённая причина, по которой прибегают к приведению типов.
Приведение ссылок
Синтаксис (Type) также работает с объектами — но в этом случае это проверка во время выполнения, а не преобразование. Приведение ссылки по сути означает «доверяю тебе, этот объект имеет тип X»:
Object o = "Hello";
String s = (String) o; // OK at runtime
System.out.println(s.length()); // 5
Object n = Integer.valueOf(7);
String bad = (String) n; // throws ClassCastException at runtimeЧтобы безопасно привести ссылку, сначала проверьте тип с помощью instanceof:
Object o = "Hello";
if (o instanceof String) {
String s = (String) o; // guaranteed safe
System.out.println(s.length());
}Сопоставление с образцом для instanceof (современная Java) позволяет выполнить проверку и приведение за один шаг. Приведение ссылок подробно рассматривается в разделе ООП и полиморфизм.
Рабочий пример
Когда компилятор «помогает» — и когда нет
Важный случай, на который стоит обратить внимание: арифметические операции над byte, short или char автоматически повышаются до int перед выполнением. Результат имеет тип int:
byte a = 10;
byte b = 20;
// byte sum = a + b; // compile error: result is int
byte sum = (byte) (a + b); // explicit cast neededЭто застаёт всех врасплох в первый раз. Либо сохраняйте результат в int, либо выполняйте явное приведение обратно.
Практические правила
- Расширяйте свободно — приведение не нужно, потерь нет.
- Сужайте с приведением и проверкой — убедитесь, что значение действительно помещается в целевой тип.
- Для вещественного деления целых чисел приведите один операнд к
double. - Для денежных расчётов не используйте
doubleвовсе — используйтеBigDecimal, чтобы избежать ошибок округления в двоичном представлении с плавающей точкой.
Что дальше
Операторы Java — полный обзор всех операторов языка.