Короткий ответ
Полиморфизм (дословно «много форм») — принцип ООП, при котором одно и то же имя метода (или один и тот же код) работает с объектами разных типов, проявляя себя по-разному. В Java различают два вида: полиморфизм времени компиляции — перегрузка методов, и полиморфизм времени выполнения — переопределение методов, который называют также динамической диспетчеризацией.
Как это работает подробнее
Механизм runtime-полиморфизма: переменная имеет тип родительского класса, а указывает на объект наследника. При вызове переопределённого метода JVM определяет фактический тип объекта во время выполнения и вызывает реализацию именно этого класса.
- Перегрузка (overloading). В одном классе несколько методов с одинаковым именем и разными параметрами; нужный вариант выбирает компилятор по типам переданных аргументов.
- Переопределение (overriding). Наследник заменяет реализацию унаследованного метода, сохраняя сигнатуру; выбор реализации происходит на этапе выполнения.
- Практический эффект. Один метод, принимающий
Animal, работает сDog,Cat,Horse: код един, а поведение различно. Новый подкласс добавляется без изменения существующих методов.
Пример кода
Main.java
class Animal {
void voice() {
System.out.println("Звук");
}
}
class Dog extends Animal {
@Override
void voice() {
System.out.println("Гав");
}
}
public class Main {
// перегрузка: выбор версии на этапе компиляции
static int sum(int a, int b) {
return a + b;
}
static double sum(double a, double b) {
return a + b;
}
public static void main(String[] args) {
Animal a = new Dog();
a.voice(); // «Гав» — динамическая диспетчеризация
sum(1, 2); // int-версия
sum(1.5, 2.5); // double-версия
}
}Что использовать на практике
- Кодить на уровне родительского типа (
Animal), а конкретных наследников подставлять во время выполнения. - Проектировать API так, чтобы новый подкласс добавлялся без изменения существующих методов.
- Помнить, что при перегрузке версия метода выбирается статически по типам аргументов ещё на этапе компиляции.
Подводные камни
- Называть перегрузку полиморфизмом времени выполнения: выбор перегруженного метода делает компилятор.
- Думать, что при переопределении вызванный метод определяет тип ссылки: решает фактический тип объекта.
- Менять типы параметров, «переопределяя» метод родителя, — это будет перегрузка, а не переопределение.
Как отвечать на собеседовании
- Каркас ответа: дайте определение полиморфизма → разделите на перегрузку (compile-time) и переопределение (runtime) → объясните динамическую диспетчеризацию на примере
Animal a = new Dog()→ покажите выгоду: единый код и расширяемость.