Приведение типов в Java: учебные примеры и ошибки школьника
💻 Информатика · 10 класс
Как школьнику разобраться в расширении, сужении и cast в Java. Округление, byte, деление, строки и объекты: разобранные примеры и пять заданий с ответами.

В первых школьных программах на Java важно различать тип исходного значения и тип результата. Например, запись среднего балла в переменную double ещё не делает деление дробным. Этот урок для школьников разбирает расширение, сужение и явное приведение — cast. В спецификации Java существуют и другие преобразования, включая boxing и unboxing; классификация не ограничивается двумя видами. Примеры относятся к правилам Java SE 17.
Расширяющие преобразования: когда Java всё делает сама
Расширяющие числовые преобразования допустимы неявно в подходящем контексте, например при присваивании. Но название «расширение» не гарантирует сохранения точного значения при переходе из целых чисел в числа с плавающей точкой. Допустимые направления показаны ниже:
| Из | В (неявное расширение) |
|---|---|
| byte | short, int, long, float, double |
| short, char | int, long, float, double |
| int | long, float, double |
| long | float, double |
| float | double |
Тип char расширяется до int по коду символа в Unicode: 'A' имеет код 65, поэтому 'A' + 2 — это уже арифметика над int и даёт 67. При переходах int → float, long → float и long → double возможно округление. Например, int 16777217 после преобразования к float представляется как 16777216: в этом диапазоне соседние значения float уже не различают каждое целое. Поэтому для количества предметов или точных счётчиков не стоит выбирать дробный тип только потому, что он считается «шире».
Сужающие преобразования и потеря данных
При сужении обычно нужен явный cast: (тип) значение. Для присваивания допустимой константы есть исключение: byte count = 42; компилируется без cast, потому что значение константы помещается в byte. Но int count = 42; byte small = count; без cast недопустимо: обычная переменная int не является константным выражением. Разные виды сужения работают по разным правилам, а не всегда просто отбрасывают биты.
Пример 1. Переполнение byte. Тип byte занимает 8 бит и хранит диапазон от −128 до 127. Код byte b = (byte) 130; компилируется, а на этапе выполнения лишние биты отбрасываются по модулю 256: значение 130 выходит за верхнюю границу на 2, поэтому в b окажется −126 (130 − 256). Аналогично (byte) 200 даст −56. При таком числовом приведении исключение не возникает: результат определяется младшими восемью битами. По одному успешному выполнению нельзя судить, что исходное число сохранилось.
Пример 2. Отбрасывание дробной части. Выражение int n = (int) 9.99; даёт 9, а не 10: при сужении double к целому дробная часть отбрасывается с округлением к нулю (для −9.99 результат −9). Для обычного округления до ближайшего целого есть Math.round со своими правилами; результат зависит от выбранного метода. Приведённые примеры усечения относятся к конечным числам в диапазоне int. Для NaN результат приведения к int равен 0, а значения за границами диапазона, включая бесконечности, приводятся к соответствующей граничной величине int.
Приведение внутри выражений
Правила cast не отменяют правила вычисления выражений. В строке double d = 1 / 2; деление выполняется до присваивания, оба операнда — int, поэтому результат 0, который затем неявно расширяется до 0.0. Чтобы получить 0.5, нужно расширить один из операндов заранее: 1.0 / 2 или (double) 1 / 2. Порядок имеет значение: (double) (1 / 2) даёт ровно 0.0, потому что сначала выполняется целочисленное деление, а cast применяется уже к его результату.
Строки и числа: это не приведение типов
Строка в Java — объект, и между String и числами нет cast. Преобразование выполняют методы: Integer.parseInt("12") возвращает примитив int 12, Double.parseDouble("2.5") — double 2.5. Метод Integer.valueOf("12") разбирает строку и возвращает объект Integer. В арифметическом выражении такой объект может неявно распаковываться в int. Сам вызов valueOf со строкой не следует путать с boxing-преобразованием уже имеющегося примитивного значения. Некорректная строка ("abc", "4,2" с запятой) вызовет NumberFormatException, поэтому данные от пользователя преобразуют с проверкой или обработкой исключения. Обратно: String.valueOf(42) или конкатенация 42 + "" дают строку "42".
Приведение объектных типов: upcast и downcast
При приведении ссылочного выражения меняется его тип для дальнейшего использования; сам объект не превращается в объект другого класса. Расширяющий upcast автоматичен: Object obj = "строка"; — строка везде, где ждут Object. Обратный downcast требует cast: String s = (String) obj;. Если фактический объект другого типа, выполнение завершится ошибкой ClassCastException, поэтому безопасный стиль — проверка instanceof:
Object obj = Integer.valueOf(5);
if (obj instanceof String) {
String s = (String) obj; // сюда не попадём
} else {
System.out.println("Это не строка");
}Приведение к параметризованным типам возможно, но из-за стирания типов часть таких преобразований проверяется не полностью и вызывает предупреждения компилятора. Нельзя считать cast способом проверить тип каждого элемента коллекции. Подробнее — в материале о generics в Java, а про встречающиеся рядом преобразования примитивов в объекты — boxing и unboxing.
Упражнения
Задание 1
Чему равно выражение (int) 3.99 и почему не 4?
Ответ 1: 3. Явное приведение double к int отбрасывает дробную часть (округление к нулю), а не округляет по математическим правилам.
Задание 2
Что выведет код byte b = (byte) 200; System.out.println(b);?
Ответ 2: −56. Диапазон byte — от −128 до 127; значение 200 выходит за границу на 72, и по модулю 256 получается 200 − 256 = −56.
Задание 3
Чему равно значение выражения 'A' + 2?
Ответ 3: 67. Символ 'A' имеет код 65 в Unicode; в арифметическом выражении char автоматически расширяется до int, и 65 + 2 = 67.
Задание 4
Чему равно double d = 5 / 2; и как получить 2.5?
Ответ 4: 2.0: сначала выполняется целочисленное деление 5 / 2 = 2, затем 2 неявно расширяется до 2.0. Результат 2.5 дают выражения 5.0 / 2 или (double) 5 / 2 — cast должен попасть на операнд до деления.
Задание 5
Как преобразовать строку "12" в число и прибавить к нему 3?
Ответ 5: int n = Integer.parseInt("12") + 3;, результат 15. Оператор (int) для строк не работает — нужен метод parseInt, который при нечисловой строке бросит NumberFormatException.