Короткий ответ
Перегрузка (overloading) — наличие в одном классе нескольких методов с одинаковым именем и разным списком параметров; нужный вариант выбирает компилятор по типам аргументов, поэтому это полиморфизм времени компиляции. Переопределение (overriding) — изменение реализации унаследованного метода в классе-наследнике при сохранении сигнатуры; реализацию выбирает JVM по фактическому типу объекта на этапе выполнения.
Как это работает подробнее
Механизмы удобно сравнивать по нескольким осям: где происходит, как связаны сигнатуры и когда выбирается реализация.
- Где происходит. Перегрузка — внутри одного класса; переопределение — между родителем и наследником.
- Сигнатура. При перегрузке параметры обязаны отличаться; при переопределении — обязаны совпадать, а возвращаемый тип должен быть тем же или ковариантным (подтипом).
- Момент выбора. Перегрузка — на этапе компиляции; переопределение — на этапе выполнения, по фактическому типу объекта.
- Ограничения. Переопределить можно только унаследованный не-
static, не-final, не-privateметод; модификатор доступа нельзя делать строже. Перегружаются любые методы, включая статические и конструкторы. Корректное переопределение помечают аннотацией@Override.
Пример кода
OverloadVsOverride.java
class Calculator {
// перегрузка: одинаковое имя, разные параметры
int sum(int a, int b) {
return a + b;
}
double sum(double a, double b) {
return a + b;
}
}
class Animal {
void voice() {
System.out.println("Звук");
}
}
class Cat extends Animal {
// переопределение: та же сигнатура, новая реализация
@Override
void voice() {
System.out.println("Мяу");
}
}