Привет!
Сегодня мы заканчиваем серию лекций о принципах
ООП. На этом занятии поговорим о полиморфизме.
Коротко: полиморфизм это возможность работать с объектами разных типов через один общий тип, при этом каждый объект сохраняет свое поведение. Обычно он достигается через наследование: один метод может принимать родительский тип (например
Cat) и работать с любым его наследником (
Lion,
Tiger,
Cheetah), не заставляя писать отдельный метод под каждый вид.
Полиморфизм это возможность работать с несколькими типами так, будто это один и тот же тип. При этом поведение объектов будет разным в зависимости от того, к какому типу они принадлежат.
Кратко
- Полиморфизм это возможность работать с объектами разных типов через общий тип, сохраняя при этом их собственное поведение.
- Обычно достигается через наследование: класс-родитель (например
Cat) и наследники (Lion, Tiger, Cheetah).
- Один метод может принимать общий тип (
healCat(Cat cat)) и работать с любым наследником, не плодя отдельные методы.
- При вызове переопределенного метода (
run()) выполняется реализация конкретного класса, а не родителя.
- Главное преимущество: гибкость и меньше кода; единый интерфейс для многих классов.
Давай рассмотрим это утверждение подробнее.
![Полиморфизм в Java: работа с объектами разных типов как с одним]()
Что такое полиморфизм
Начнем с первой части: «возможность работать с несколькими типами так, как будто это один и тот же тип». Как разные типы могут при этом быть одним и тем же? Звучит немного странно :/
На самом деле все просто. К примеру, такая ситуация возникает при обычном использовании
наследования. Посмотрим, как это работает.
Допустим, у нас есть простой родительский класс
Cat с единственным методом
run(), то есть «бежать»:
public class Cat {
public void run() {
System.out.println("Бег!");
}
}
А теперь создадим три класса, которые наследуются от
Cat:
Lion,
Tiger и
Cheetah, обозначающие льва, тигра и гепарда.
public class Lion extends Cat {
@Override
public void run() {
System.out.println("Лев бежит со скоростью 80 км/ч");
}
}
public class Tiger extends Cat {
@Override
public void run() {
System.out.println("Тигр бежит со скоростью 60 км/ч");
}
}
public class Cheetah extends Cat {
@Override
public void run() {
System.out.println("Гепард бежит со скоростью до 120 км/ч");
}
}
Итак, у нас есть 3 класса. Давай смоделируем ситуацию, при которой мы сможем работать с ними так, как будто это один и тот же класс.
Один метод для всех типов
Представим, что кто-то из наших котов заболел, и ему нужна помощь доктора Айболита. Попробуем создать класс
Aibolit, который будет способен лечить и львов, и тигров, и гепардов.
public class Aibolit {
public void healLion(Lion lion) {
System.out.println("Лев здоров!");
}
public void healTiger(Tiger tiger) {
System.out.println("Тигр здоров!");
}
public void healCheetah(Cheetah cheetah) {
System.out.println("Гепард здоров!");
}
}
Казалось бы, проблема решена: класс написан и готов к работе. Но что мы будем делать, если захотим расширить нашу программу?
Сейчас у нас всего 3 вида: львы, тигры, и гепарды. Но в мире существует больше 40 видов кошек. Представь, что будет, если мы добавим в программу отдельные классы для манулов, ягуаров, мейн-кунов, домашних кошек и всех остальных.
![Без полиморфизма для каждого вида кошек пришлось бы писать отдельный метод]()
Сама программа, конечно, будет функционировать, но вот в класс
Aibolit придется постоянно добавлять новые методы для лечения каждого вида кошек, и в итоге он разрастется до невиданных размеров.
Здесь и проявляется свойство полиморфизма, «возможность работать с несколькими типами так, как будто это один и тот же тип». Нам не нужно создавать бесчисленное количество методов, которые будут делать одно и то же, лечить кошку.
Достаточно будет одного метода для всех случаев сразу:
public class Aibolit {
public void healCat(Cat cat) {
System.out.println("Пациент здоров!");
}
}
В метод
healCat() мы можем передавать и объекты
Lion, и
Tiger и
Cheetah, они все являются
Cat:
public class Main {
public static void main(String[] args) {
Aibolit aibolit = new Aibolit();
Lion simba = new Lion();
Tiger sherekhan = new Tiger();
Cheetah chester = new Cheetah();
aibolit.healCat(simba);
aibolit.healCat(sherekhan);
aibolit.healCat(chester);
}
}
Вывод в консоль:
Пациент здоров!
Пациент здоров!
Пациент здоров!
Вот так наш класс
Айболит может работать с разными типами, как будто это один и тот же тип.
Наглядно разницу двух подходов можно свести в таблицу:
| Подход | Класс Aibolit | Что будет при 40 видах кошек |
| Без полиморфизма | отдельный метод на каждый вид (healLion, healTiger, healCheetah и т.д.) | 40 почти одинаковых методов |
| С полиморфизмом | один метод healCat(Cat cat) | один метод на все виды |
Разное поведение у разных типов
Теперь давай разберемся со второй частью: «при этом поведение объектов будет разным в зависимости от того, к какому типу они принадлежат».
Здесь тоже все просто. В природе все кошки бегают по-разному. Как минимум, у них различается скорость бега. Среди наших трех питомцев гепард самый быстрый, а тигр и лев бегают медленнее. То есть у них отличается поведение.
Полиморфизм не только дает нам возможность использовать разные типы как один. Он при этом еще позволяет не забывать об их отличиях и сохраняет специфическое для каждого из них поведение.
Это можно понять на таком примере. Допустим, после успешного выздоровления наши коты решили на радостях немного побегать. Добавим это в наш класс
Aibolit:
public class Aibolit {
public void healCat(Cat cat) {
System.out.println("Пациент здоров!");
cat.run();
}
}
Попробуем выполнить тот же код для лечения трех зверей:
public static void main(String[] args) {
Aibolit aibolit = new Aibolit();
Lion simba = new Lion();
Tiger sherekhan = new Tiger();
Cheetah chester = new Cheetah();
aibolit.healCat(simba);
aibolit.healCat(sherekhan);
aibolit.healCat(chester);
}
И вот как будет выглядеть результат:
Пациент здоров!
Лев бежит со скоростью 80 км/ч
Пациент здоров!
Тигр бежит со скоростью 60 км/ч
Пациент здоров!
Гепард бежит со скоростью до 120 км/ч
Здесь мы наглядно видим, что специфическое поведение наших объектов сохранилось, хотя мы передали всех троих зверей в метод, «обобщив» каждого из них до
Cat. Благодаря полиморфизму Java прекрасно помнит, что это не просто три каких-то кота, а именно лев, тигр и гепард, которые бегают по-разному.
В этом заключается
главное преимущество использования полиморфизма, гибкость. Когда нам нужно создать какой-то общий для многих типов функционал, львы, тигры и гепарды превращаются просто в «котов».
Все животные разные, но в некоторых ситуациях кот есть кот, без разницы к какому виду он относится:) Вот тебе видеоподтверждение.
Когда же это «обобщение» не требуется, и нам наоборот нужно, чтобы поведение у видов отличалось, каждый тип ведет себя по-своему.
Благодаря полиморфизму, ты создаешь единый интерфейс (набор методов) для широкого набора классов. За счет этого снижается сложность программ.
Если бы мы даже расширили программу до 40 видов кошек, у нас все равно сохранился бы максимально простой интерфейс, один метод
run() для всех 40 кошек. Подробнее о полиморфизме можно прочитать в
документации Oracle (Polymorphism).
Читайте также
Вопросы и ответы
Что такое полиморфизм в Java?
Это возможность работать с объектами разных типов через один общий тип, при этом каждый объект сохраняет свое поведение. Обычно реализуется через наследование.
Как полиморфизм связан с наследованием?
Наследники (например
Lion,
Tiger) являются подтипами родителя (
Cat), поэтому их можно передавать туда, где ожидается родительский тип. Это и дает работу с разными типами как с одним.
Зачем нужен полиморфизм?
Он убирает дублирование: вместо отдельного метода на каждый тип пишут один метод для общего типа. Код становится гибче и проще поддерживается.
Что происходит при вызове переопределенного метода?
Выполняется реализация того класса, к которому реально принадлежит объект, а не родителя. Например,
cat.run() у объекта
Lion выведет поведение льва.
Чем полиморфизм отличается от простого наследования?
Наследование позволяет переиспользовать код родителя. Полиморфизм добавляет к этому возможность обращаться к разным наследникам единообразно, через общий тип, с сохранением их поведения.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ