Приведение типов
В прошлом уроке среднее двух целых получилось 2.0, а не 2.5. Чтобы это исправить, нужно знать, как Java переводит число из одного типа в другой.
Калькулятор Java помнит тип каждого числа, а тип похож на коробку определённой формы. В коробке long больше места, чем в коробке int, а в коробке int нет отделения для дробной части. Из маленькой коробки число всегда можно переложить в большую. Из большой в маленькую — только если что-то отрезать, и 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
}
}Давайте разберём программу по строкам:
long big = count;кладётintв коробкуlong. Коробка больше, и Java перекладывает число сама.int whole = (int) price;кладётdoubleв коробкуint. Для дробной части там нет места, поэтому перед значением стоит(int): так вы разрешаете её отрезать.System.out.println(big)печатает3: число не изменилось.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 сужение не делает:
double price = 4.75;
int whole = price; // ✗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:
int total = 5;
int count = 2;
System.out.println((double) total / count); // 2.5
System.out.println(count * 2.5); // 5.0(double) totalпревращает5в5.0. Сама переменнаяtotalостаётсяint.- Дальше
5.0 / count— выражение сintиdouble. Java расширяетcountдоdouble, деление становится дробным, и получается2.5. count * 2.5печатает5.0: результат имеет типdouble, хотя он целый.
Так и получается правильное среднее: 2.5 вместо 2.0.
Частая ошибка
Скобки поставили вокруг всего деления:
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.