$ sudo teach IT
МОДУЛЬ 2 · УРОК 6

Преобразование типов

Иногда нужно превратить одно значение в другой тип: число в строку, целое в дробное, дробное в целое. В этом уроке мы разберём, как Java преобразует типы, какие преобразования безопасны, а какие теряют данные.

⏱ ~20 минут 🎓 Для начинающих 📌 Финал модуля 2

🔄 Зачем нужны преобразования типов

Представьте, что у вас есть число 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 → автоматически become int в выражениях
  • Если один операнд long → другой become long
  • Если один операнд float → другой become float
  • Если один операнд double → другой become double

⚠️ Частая ошибка: 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 → double
  • char → int → long → float → double
  • Любой примитив → String (через +)

⚠️ Явные (требуют cast, возможна потеря данных)

  • double → float → long → int → short → byte
  • int → 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 автоматически become int
  • Integer.parseInt("42") — строку в число; String.valueOf(42) — число в строку
  • Конкатенация + автоматически приводит к строке

Далее: Модуль 3: Условные конструкции — if/else, switch, тернарный оператор →

Проверяем понимание

6 вопросов

Конвертер температуры с вводом

Premium