В чем разница между перегрузкой метода и переопределением метода

«В чем разница между перегрузкой метода и переопределением метода» — вопрос из категории ООП, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Перегрузка (Overloading) и переопределение (Overriding) — это две формы полиморфизма в ООП, решающие разные задачи.

Перегрузка метода (Method Overloading)

  • Что это: Возможность иметь несколько методов в одном классе с одинаковым именем, но разными параметрами (разное количество, тип или порядок параметров).
  • Цель: Предоставить удобные интерфейсы для выполнения одной и той же логики с разными входными данными.
  • Когда определяется: На этапе компиляции (статический полиморфизм). Компилятор решает, какой именно метод вызвать, основываясь на сигнатуре вызова.
  • Пример на Java:
    public class Calculator {
    // Перегрузка: два метода с именем 'add', но разными параметрами
    public int add(int a, int b) {
        return a + b;
    }
    public double add(double a, double b) {
        return a + b;
    }
    public int add(int a, int b, int c) {
        return a + b + c;
    }
    }
    // Использование
    Calculator calc = new Calculator();
    calc.add(2, 3);      // Вызовет add(int, int)
    calc.add(2.5, 3.7);  // Вызовет add(double, double)
    calc.add(1, 2, 3);   // Вызовет add(int, int, int)

Переопределение метода (Method Overriding)

  • Что это: Предоставление новой, специфичной реализации метода в дочернем классе, который уже определен в родительском классе.
  • Цель: Изменить или расширить поведение, унаследованное от родителя, в соответствии с логикой дочернего класса.
  • Когда определяется: На этапе выполнения (динамический полиморфизм). JVM решает, какую реализацию метода вызвать, основываясь на фактическом типе объекта (а не на типе ссылки).
  • Правила: Сигнатура метода (имя, тип и порядок параметров, возвращаемый тип) должна совпадать. В Java используется аннотация @Override.
  • Пример на Java:
    
    class Animal {
    public void makeSound() {
        System.out.println("Some generic animal sound");
    }
    }

class Dog extends Animal { @Override // Аннотация указывает на переопределение public void makeSound() { System.out.println("Woof! Woof!"); } }

class Cat extends Animal { @Override public void makeSound() { System.out.println("Meow!"); } }

// Использование Animal myAnimal = new Animal(); myAnimal.makeSound(); // "Some generic animal sound"

myAnimal = new Dog(); // Ссылка типа Animal, объект типа Dog myAnimal.makeSound(); // "Woof! Woof!" (вызвана реализация из Dog)

myAnimal = new Cat(); myAnimal.makeSound(); // "Meow!" (вызвана реализация из Cat)



**Сводная таблица различий:**
| Критерий | Перегрузка (Overloading) | Переопределение (Overriding) |
| :--- | :--- | :--- |
| **Классы** | В пределах одного класса. | В иерархии наследования (родительский → дочерний). |
| **Сигнатура метода** | Должна **различаться** (параметры). | Должна **совпадать**. |
| **Тип возвращаемого значения** | Может отличаться. | Должен быть совместим (ковариантен). |
| **Модификаторы доступа** | Могут отличаться. | Нельзя сужать (например, с `protected` до `private`). |
| **Связывание** | Статическое (во время компиляции). | Динамическое (во время выполнения). |
| **Аннотация `@Override`** | Не используется (вызовет ошибку). | Рекомендуется для ясности и проверки компилятором. |