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: Перевантаження і наслідування.
Якщо в базовому класі оголошено метод, а в підкласі ви оголошуєте метод із тим самим імʼям, але іншою сигнатурою, це буде перевантаження, а не перевизначення. Це часто плутають! Докладніше про це — у наступній лекції.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ