Полиморфизм
Subtype polymorphism позволяет обращаться к разным реализациям через общий тип. Переопределённый экземплярный метод выбирается по runtime-типу объекта.
interface Formatter {
String format(long value);
}
final class DecimalFormatter implements Formatter {
public String format(long value) {
return Long.toString(value);
}
}
final class HexFormatter implements Formatter {
public String format(long value) {
return Long.toHexString(value);
}
}
Formatter formatter = new HexFormatter();
System.out.println(formatter.format(42)); // 2aКлиент знает контракт Formatter, а не проверяет реализацию через instanceof.
Что выбирается когда
| Конструкция | Выбор |
|---|---|
| override instance-метода | runtime по объекту |
| overload | compile time по объявленным типам аргументов |
static-метод | compile time по типу ссылки/имени класса |
| поле | compile time; поля скрываются |
private/final метод | переопределения нет |
void print(Object value) { System.out.println("object"); }
void print(String value) { System.out.println("string"); }
Object value = "text";
print(value); // object: overload выбран при компиляцииПодтип должен сохранять обещания базового типа: не усиливать предусловия и не разрушать ожидаемые свойства. Иначе динамическая подстановка формально компилируется, но ломает клиента.
Ошибки
- путать overload с override;
- делать type switch по всем реализациям вместо виртуального вызова;
- менять смысл метода в наследнике;
- ожидать полиморфизм полей или static-методов.
На собеседовании
По чему выбирается override? По фактическому классу объекта.
По чему выбирается overload? По compile-time типам и доступным сигнатурам.
Можно ли переопределить static-метод? Нет, его можно только скрыть.
Зачем контракту Liskov? Чтобы объект подтипа безопасно заменял базовый тип.
Связано: Переопределение Java, Перегрузка Java, Принципы SOLID.