Преобразование типов
Иногда нужно превратить одно значение в другой тип: число в строку, целое в дробное, дробное в целое. В этом уроке мы разберём, как Java преобразует типы, какие преобразования безопасны, а какие теряют данные.
🔄 Зачем нужны преобразования типов
Представьте, что у вас есть число int age = 25;, и вы хотите вывести его в строке: "Мне 25 лет". Просто сложить "Мне " + age + " лет" — сработает автоматически (Java сама превратит int в строку). Но что если нужно сделать наоборот — строку превратить в число? Или целое число — в дробное?
Преобразование типов (type casting) — это процесс превращения значения одного типа в значение другого типа. Есть два вида:
- Неявное (widening) — безопасное, автоматическое, без потери данных
- Явное (narrowing) — потенциально опасное, требует ручного указания (cast)
📐 Неявное расширение (widening)
Если значение «влезает» в целевой тип без потери данных, Java делает это автоматически:
public class Widening {
public static void main(String[] args) {
// byte → short → int → long → float → double
byte b = 100;
int i = b; // byte → int (автоматически)
long l = i; // int → long (автоматически)
double d = l; // long → double (автоматически)
int x = 42;
double y = x; // int → double (42.0 — автоматически)
char c = 'A';
int code = c; // char → int (65 — автоматически)
System.out.println(y); // 42.0
System.out.println(code); // 65
}
}
Цепочка безопасных расширений:
byte
→ short
→ int
→ long
→ float
→ double
Каждое преобразование безопасно — данных не теряется
Почему int → long безопасно? Потому что long больше int и может вместить любое значение int. Почему int → double безопасно? Потому что double может представить любое целое число до 2⁵³ точно.
⚠️ Явное сужение (narrowing)
Если значение может не влезть в целевой тип или потерять точность, Java требует явного указания через cast (приведение типа):
public class Narrowing {
public static void main(String[] args) {
// double → int (теряется дробная часть)
double pi = 3.14;
int rounded = (int) pi; // 3 — дробная часть отброшена!
System.out.println(rounded); // 3
// long → int (может переполниться)
long big = 3_000_000_000L;
int truncated = (int) big; // -1294967296 (переполнение!)
System.out.println(truncated);
// double → float (теряется точность)
double precise = 3.141592653589793;
float less = (float) precise; // 3.1415927 (менее точно)
// int → byte (может переполниться)
int x = 200;
byte b = (byte) x; // -56 (переполнение!)
}
}
Явное сужение — это ответственность программиста. Java предупреждает: «Это опасно, ты уверен?». Cast через (тип) — это ваш ответ: «Да, я понимаю, что делаю».
Типичные ситуации, когда нужен cast:
double → int— отбросить дробную частьlong → int— если знаете, что значение влезаетint → byte/short— если знаете, что значение в диапазонеdouble → float— если нужна экономия памяти
⬆️ Автоматическое продвижение (type promotion)
В арифметических выражениях Java автоматически «продвигает» меньшие типы до larger:
public class Promotion {
public static void main(String[] args) {
byte a = 10;
byte b = 20;
// byte c = a + b; // ОШИБКА! a + b автоматически becomes int!
int c = a + b; // OK: a и b продвинуты до int
System.out.println(c); // 30
// В выражении int + double → double
int x = 5;
double y = 2.5;
double result = x + y; // x автоматически becomes double
System.out.println(result); // 7.5
}
}
Правила продвижения:
byte,short,char→ автоматически becomeintв выражениях- Если один операнд
long→ другой becomelong - Если один операнд
float→ другой becomefloat - Если один операнд
double→ другой becomedouble
⚠️ Частая ошибка: byte c = a + b; — ошибка! Даже если a и b — byte, их сумма автоматически become int. Нужно либо int c = a + b;, либо byte c = (byte)(a + b);.
📝 Преобразование строк: String ↔ числа
Часто нужно превратить строку в число (например, из пользовательского ввода) или число в строку (для вывода):
Строка → число
public class StringToNumber {
public static void main(String[] args) {
// Строка → int
String numStr = "42";
int num = Integer.parseInt(numStr);
System.out.println(num + 1); // 43
// Строка → double
String piStr = "3.14";
double pi = Double.parseDouble(piStr);
System.out.println(pi * 2); // 6.28
// Строка → long
String bigStr = "1234567890";
long big = Long.parseLong(bigStr);
// ОШИБКА! Строка не является числом
try {
int invalid = Integer.parseInt("hello");
} catch (NumberFormatException e) {
System.out.println("Это не число!");
}
}
}
Число → строка
public class NumberToString {
public static void main(String[] args) {
int age = 25;
// Способ 1: String.valueOf()
String s1 = String.valueOf(age);
// Способ 2: метод класса-обёртки
String s2 = Integer.toString(age);
// Способ 3: конкатенация (самый простой)
String s3 = "" + age;
// Способ 4: formatted string
String s4 = String.format("Мне %d лет", age);
System.out.println(s4); // Мне 25 лет
}
}
Обратите внимание: Integer.parseInt() выбрасывает NumberFormatException, если строка не является числом. В реальных программах это нужно обрабатывать (мы разберём исключения в модуле 9).
🔗 Автоматическое приведение к строке
Когда вы используете + со строкой, Java автоматически превращает другой операнд в строку:
public class AutoString {
public static void main(String[] args) {
int age = 25;
double price = 9.99;
boolean active = true;
char letter = 'A';
// Все работают автоматически:
String s1 = "Возраст: " + age; // "Возраст: 25"
String s2 = "Цена: " + price; // "Цена: 9.99"
String s3 = "Активен: " + active; // "Активен: true"
String s4 = "Буква: " + letter; // "Буква: A"
// Порядок имеет значение!
System.out.println(1 + 2 + "abc"); // 3abc (сложение, потом конкатенация)
System.out.println("abc" + 1 + 2); // abc12 (конкатенация)
}
}
Это удобно, но нужно понимать порядок операций. 1 + 2 + "abc" — сначала 1 + 2 = 3, потом 3 + "abc" = "3abc".
🗺️ Полная карта преобразований
✅ Автоматические (безопасные)
byte → short → int → long → float → doublechar → int → long → float → double- Любой примитив →
String(через+)
⚠️ Явные (требуют cast, возможна потеря данных)
double → float → long → int → short → byteint → char(если значение в диапазоне 0-65535)String → int/double/long(черезparseInt,parseDouble)
🛠️ Практический пример: конвертер единиц
public class UnitConverter {
public static void main(String[] args) {
// Км → метры
double km = 1.5;
int meters = (int) (km * 1000); // cast нужен: double → int
System.out.println(km + " км = " + meters + " м");
// Кг → граммы
double kg = 2.5;
int grams = (int) (kg * 1000);
System.out.println(kg + " кг = " + grams + " г");
// Фаренгейт → Цельсий
int fahrenheit = 72;
double celsius = (fahrenheit - 32.0) * 5.0 / 9.0;
System.out.println(fahrenheit + "°F = " + String.format("%.1f", celsius) + "°C");
// Секунды → часы, минуты, секунды
int totalSeconds = 3661;
int hours = totalSeconds / 3600;
int minutes = (totalSeconds % 3600) / 60;
int seconds = totalSeconds % 60;
System.out.println(totalSeconds + " сек = " + hours + "ч " + minutes + "м " + seconds + "с");
}
}
✅ Итоги урока
- Неявное (widening) — безопасное, автоматическое:
int → long → double - Явное (narrowing) — требует cast
(тип), может потерять данные double → intотбрасывает дробную часть (не округляет!)long → intпри переполнении даёт «обёрнутое» значение- В выражениях
byte,short,charавтоматически becomeint Integer.parseInt("42")— строку в число;String.valueOf(42)— число в строку- Конкатенация
+автоматически приводит к строке
Далее: Модуль 3: Условные конструкции — if/else, switch, тернарный оператор →
Проверяем понимание
6 вопросов