Перейти к содержимому
Теория · Операторы и выражения · урок 3 из 8

Приведение типов

В прошлом уроке среднее двух целых получилось 2.0, а не 2.5. Чтобы это исправить, нужно знать, как Java переводит число из одного типа в другой.

Калькулятор Java помнит тип каждого числа, а тип похож на коробку определённой формы. В коробке long больше места, чем в коробке int, а в коробке int нет отделения для дробной части. Из маленькой коробки число всегда можно переложить в большую. Из большой в маленькую — только если что-то отрезать, и Java требует, чтобы вы подтвердили это явно:

JAVA
public class Main {
    public static void main(String[] args) {
        int count = 3;
        long big = count;
        double price = 4.75;
        int whole = (int) price;
        System.out.println(big);   // 3
        System.out.println(whole); // 4
    }
}

Давайте разберём программу по строкам:

  1. long big = count; кладёт int в коробку long. Коробка больше, и Java перекладывает число сама.
  2. int whole = (int) price; кладёт double в коробку int. Для дробной части там нет места, поэтому перед значением стоит (int): так вы разрешаете её отрезать.
  3. System.out.println(big) печатает 3: число не изменилось.
  4. System.out.println(whole) печатает 4: от 4.75 осталась только целая часть.

Аналогия с коробками неточна в одном: число не перекладывают, а копируют. После (int) price в переменной price по-прежнему лежит 4.75.

Расширение — автоматически

Расширяющее преобразование переводит значение в тип с более широким диапазоном. Для чисел этой темы цепочка такая: int → long → double.

  • Java делает его сама: при присваивании, как в long big = count;, и в вычислениях.
  • Число при этом остаётся тем же: 3 в long — это 3, а в double — 3.0.

Если в одном выражении встретились int и double, Java сначала расширяет int до double и только потом считает. Результат тоже получается double: 3 * 2.5 равно 7.5, а 7 / 2.0 равно 3.5.

Сужение — только явно

Сужающее преобразование переводит значение в тип с более узким диапазоном: double в int, long в int. Часть числа при этом может пропасть, поэтому сама Java сужение не делает:

JAVA
double price = 4.75;
int whole = price; // ✗
TEXT
error: incompatible types: possible lossy conversion from double to int

Компилятор отказывается класть double в int: при таком преобразовании возможна потеря данных. Чтобы он согласился, нужно приведение типа — имя нужного типа в скобках перед значением: int whole = (int) price;. Так вы говорите компилятору: «знаю, что часть числа может пропасть, и согласен».

Из double в int

Дробная часть отбрасывается, а не округляется, как и при целом делении:

  • (int) 4.75 равно 4, хотя 4.75 ближе к пяти;
  • (int) -4.75 равно -4: результат сдвигается к нулю.

Из long в int

Это тоже сужение: в long помещаются числа, которых в int нет. Без (int) компилятор ответит той же ошибкой, только со словами from long to int. Если значение помещается в int, приведение его не меняет.

Приведение в выражении

Приведение действует только на значение, которое стоит сразу после скобок. Этим пользуются, чтобы получить дробное деление из двух int:

JAVA
int total = 5;
int count = 2;
System.out.println((double) total / count); // 2.5
System.out.println(count * 2.5);            // 5.0
  1. (double) total превращает 5 в 5.0. Сама переменная total остаётся int.
  2. Дальше 5.0 / count — выражение с int и double. Java расширяет count до double, деление становится дробным, и получается 2.5.
  3. count * 2.5 печатает 5.0: результат имеет тип double, хотя он целый.

Так и получается правильное среднее: 2.5 вместо 2.0.

Частая ошибка

Скобки поставили вокруг всего деления:

JAVA
public class Main {
    public static void main(String[] args) {
        int total = 5;
        int count = 2;
        double average = (double) (total / count); // ✗
        System.out.println(average);               // 2.0
    }
}

Программа печатает 2.0. Скобки заставили Java сначала выполнить total / count как целое деление и получить 2. Только потом приведение превратило 2 в 2.0, а дробь пропала ещё раньше. Приводите одно из чисел, а не результат: (double) total / count.

Главное

  • Расширение (int → long → double) Java делает сама, без приведения.
  • Сужение (double в int, long в int) требует приведения: без (int) код не компилируется.
  • (int) отбрасывает дробную часть без округления: (int) 4.75 — это 4.
  • Приведение действует на ближайшее значение: (double) total / count даёт 2.5, а (double) (total / count) даёт 2.0.