W3docs

Приведение типов в 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 around

byte занимает 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) позволяет выполнить проверку и приведение за один шаг. Приведение ссылок подробно рассматривается в разделе ООП и полиморфизм.

Рабочий пример

java— editable, runs on the server

Когда компилятор «помогает» — и когда нет

Важный случай, на который стоит обратить внимание: арифметические операции над 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 — полный обзор всех операторов языка.

Практика

Практика
Какие преобразования требуют явного приведения?
Какие преобразования требуют явного приведения?
Was this page helpful?