JavaRush /Курси /JAVA 25 SELF /Перевантаження методів (overloading)

Перевантаження методів (overloading)

JAVA 25 SELF
Рівень 18 , Лекція 1
Відкрита

1. Перевантаження методів

Перевантаження методів (method overloading) — це можливість оголосити в одному класі кілька методів з однаковою назвою, але з різними списками параметрів (типами, кількістю або порядком аргументів). Коли ви викликаєте такий метод, компілятор сам вирішує, яку версію використати, залежно від переданих аргументів.

Аналогія з життя

Уявіть, що ви телефонуєте до служби підтримки банку. Ви можете зателефонувати за різними номерами — для фізичних осіб, для юридичних осіб, для VIP-клієнтів. Номери різні, але мета одна — отримати допомогу. У програмуванні перевантаження методів — це як один номер підтримки, який автоматично зʼєднує вас із потрібним оператором залежно від того, яке у вас запитання (або які параметри ви передали).

Синтаксис перевантаження у Java

У Java перевантаження методів реалізується дуже просто: оголошуєте кілька методів з однією й тією самою назвою, але різними параметрами.

Важливе правило:
Перевантаження розрізняється тільки за списком параметрів (тип, кількість, порядок).
Перевантаження лише за типом, що повертається, не допускається!
Компілятор не зможе відрізнити методи, якщо в них однакова назва та однакові параметри, навіть якщо тип, що повертається, різний.

Простий приклад

public class Printer {
    // Виведення цілого числа
    void print(int x) {
        System.out.println("int: " + x);
    }

    // Виведення рядка
    void print(String s) {
        System.out.println("String: " + s);
    }

    // Виведення двох чисел
    void print(int x, int y) {
        System.out.println("int, int: " + x + ", " + y);
    }
}

Використання:

Printer printer = new Printer();
printer.print(42);           // викличе print(int x)
printer.print("Привіт!");    // викличе print(String s)
printer.print(5, 10);        // викличе print(int x, int y)

Компілятор сам визначає, який метод викликати, з огляду на передані аргументи.

2. Як компілятор обирає потрібний метод

Коли ви викликаєте перевантажений метод, компілятор аналізує список аргументів і шукає найвідповіднішу версію.

Критерії вибору:

  • Збіг за кількістю аргументів.
  • Збіг за типом кожного аргументу (або можливість перетворити тип, наприклад, int double).
  • Якщо підходить кілька методів, обирається найспецифічніший.

Приклад:

public class OverloadDemo {
    void show(int x) {
        System.out.println("show(int): " + x);
    }

    void show(double x) {
        System.out.println("show(double): " + x);
    }

    public static void main(String[] args) {
        OverloadDemo demo = new OverloadDemo();
        demo.show(5);      // show(int): 5
        demo.show(5.5);    // show(double): 5.5
    }
}

Якщо викликати demo.show(5), компілятор обере show(int). Якщо викликати з 5.5 — обере show(double).

Перетворення типів

Якщо відповідного методу немає, компілятор спробує перетворити типи аргументів (наприклад, int double), але лише якщо це можливо і не створює неоднозначності.

void print(double x) { /* ... */ }

print(5); // int 5 перетворюється на double 5.0

Перевантаження лише за типом, що повертається, — не працює!

Часто новачки намагаються зробити так:

// Помилка! Таке перевантаження неможливе
int sum(int x, int y) { return x + y; }
double sum(int x, int y) { return (double) (x + y); }

Компілятор не зрозуміє, який метод ви хочете викликати, якщо просто напишете sum(2, 3).
Запамʼятайте: перевантаження методів можливе лише за параметрами, а не за типом, що повертається!

3. Перевантаження конструкторів

Можна перевантажувати не лише звичайні методи, а й конструктори!

public class Person {
    String name;
    int age;

    // Конструктор лише з імʼям
    public Person(String name) {
        this.name = name;
        this.age = 0; // за замовчуванням
    }

    // Конструктор з імʼям і віком
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Використання:

Person p1 = new Person("Анна");
Person p2 = new Person("Борис", 25);

4. Практичні приклади

Calculator із перевантаженням

Напишімо клас Calculator, який уміє додавати числа різного типу й кількості.

public class Calculator {
    // Додавання двох цілих чисел
    int add(int a, int b) {
        return a + b;
    }

    // Додавання трьох цілих чисел
    int add(int a, int b, int c) {
        return a + b + c;
    }

    // Додавання двох чисел типу double
    double add(double a, double b) {
        return a + b;
    }
}

Використання:

Calculator calc = new Calculator();

System.out.println(calc.add(2, 3));         // 5
System.out.println(calc.add(1, 2, 3));      // 6
System.out.println(calc.add(2.5, 3.1));     // 5.6

Перевантаження методів у стандартній бібліотеці

Ви вже стикалися з перевантаженням, навіть якщо не помічали цього. Наприклад, метод println у System.out перевантажений для різних типів:

System.out.println("Привіт");  // println(String)
System.out.println(123);       // println(int)
System.out.println(3.14);      // println(double)
System.out.println(true);      // println(boolean)

Відкрийте вихідний код класу PrintStream — побачите десятки перевантажених версій println.

5. Коли використовувати перевантаження

Перевантаження методів — потужний інструмент, але застосовуйте його з розумом. Воно зручне, коли:

  • Логіка методу однакова, але параметри можуть відрізнятися.
  • Хочете зробити API класу зручнішим і гнучкішим.
  • Потрібно підтримати старі й нові варіанти виклику методу.

Приклад із життя:
У нашому навчальному застосунку (наприклад, у менеджері завдань) можна реалізувати метод для додавання завдання з різними параметрами:

public class TaskManager {
    void addTask(String description) { ... }
    void addTask(String description, int priority) { ... }
    void addTask(String description, int priority, String deadline) { ... }
}

Такий підхід не лише зручний для того, хто використовує ваш код, а й робить клас гнучким щодо майбутніх змін.

6. Перевантаження і varargs (змінна кількість аргументів)

У Java є можливість оголосити метод зі змінною кількістю параметрів за допомогою ... (varargs):

void printAll(String... messages) {
    for (String msg : messages) {
        System.out.println(msg);
    }
}

Тепер можна викликати:

printAll("Привіт");
printAll("Один", "Два", "Три");

Перевантаження з varargs теж можливе, але будьте обережні: якщо є два методи, і один із них — з varargs, а інший — з фіксованою кількістю параметрів, компілятор спочатку намагатиметься знайти точний збіг.

7. Типові помилки під час перевантаження методів

Помилка № 1: Плутанина з типами аргументів.
Якщо у вас є методи void process(int x) і void process(double x), виклик process(5) звернеться до першої версії, а process(5.0) — до другої. Але якщо викликати process(5L), компілятор шукатиме найкращу відповідність і може обрати неочевидний варіант (або взагалі повідомити про неоднозначність).

Помилка № 2: Перевантаження з автобоксингом.
Якщо у вас є void foo(Integer x) і void foo(Long x), виклик foo(5) спричинить помилку компіляції — компілятор не знає, який метод обрати, адже 5 можна перетворити і на Integer, і на Long.

Помилка № 3: Перевантаження лише за типом, що повертається.
Як уже зазначалося вище, методи, що відрізняються лише типом, який повертається, не можуть бути перевантажені.

Помилка № 4: Перевантаження і наслідування.
Якщо в базовому класі оголошено метод, а в підкласі ви оголошуєте метод із тим самим імʼям, але іншою сигнатурою, це буде перевантаження, а не перевизначення. Це часто плутають! Докладніше про це — у наступній лекції.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ