Полиморфизм

Тема дорожной карты · Java

Полиморфизм в Java — это принцип объектно-ориентированного программирования, позволяющий одному интерфейсу или ссылочному типу представлять множество конкретных реализаций, что даёт возможность коду работать с объектами разных классов через унифицированную абстракцию. Java поддерживает две формы полиморфизма: полиморфизм времени компиляции (статический) через перегрузку методов — несколько методов с одним именем, но разными сигнатурами параметров в одном классе — и полиморфизм времени выполнения (динамический) через переопределение методов, когда подкласс, помеченный @Override, предоставляет специализированную реализацию, диспетчеризуемую JVM через invokevirtual на основе реального типа объекта. Полиморфизм времени выполнения лежит в основе ключевых Java-паттернов: List<Animal> может хранить Dog, Cat или любой подтип; Lambda-выражение Comparator<T> является полиморфной реализацией функционального интерфейса; а внедрение зависимостей Spring опирается на Polymorphism для замены реализаций @Service или @Repository без изменения клиентского кода. Полиморфизм на основе интерфейсов в Java дополнительно обогащается default-методами (Java 8+), обеспечивающими компоновку в стиле миксина, тогда как Sealed Classes (Java 17+) и Pattern Matching в switch позволяют исчерпывающую, типобезопасную диспетчеризацию по замкнутым иерархиям полиморфизма. Глубокое понимание Polymorphism в Java является обязательным знанием для использования Generics, Collections framework, иерархий тестов JUnit 5, мокирования с Mockito и каждого корпоративного фреймворка, связывающего поведение через интерфейсы.

Как это работает

Полиморфизм в Java строится на классах, наследовании (extends), интерфейсах (implements), полиморфизме (override + динамическая диспетчеризация), инкапсуляции (private-поля + public-методы), композиции (предпочтительнее наследования). Современная Java добавляет records (immutable носители данных), sealed классы/интерфейсы (закрытые иерархии для pattern matching), default-методы интерфейсов (эволюция без слома implementers).

Когда применять

Композиция (класс has-a) лучше наследования (класс is-a) по умолчанию — Liskov substitution исключает многие "is-a", выглядящие интуитивно. Records — для immutable data-классов. Sealed-типы — когда иерархия конечна (Shape — это Circle, Square или Triangle). Избегайте глубоких иерархий (>2-3 уровней = сигнал плохого дизайна).

Типичные ошибки

Ловушки Полиморфизм: глубокие иерархии наследования, в которых "find usages" IDE не разберётся; mutable-поля без thread-safety на shared-объектах; override equals без hashCode (сломано в любом HashMap); toString сущности случайно выставляет колонку БД (утечка в логи); абстрактные базовые классы, смешивающие concern (разделяйте).

Связанные понятия

Полезные ресурсы