JavaRush /Курсы /JAVA 25 SELF /Использование полиморфизма на практике

Использование полиморфизма на практике

JAVA 25 SELF
18 уровень , 3 лекция
Открыта

1. Полиморфизм в коллекциях: зачем он нужен?

Давайте начнём с вопроса: «А зачем вообще нужен полиморфизм в реальных программах?»

Представьте себе зоопарк. У вас есть базовый класс Animal, а также куча наследников: Dog, Cat, Cow, Parrot и даже Platypus (утконос, для любителей экзотики). Каждый из них умеет издавать звук (makeSound()), но делает это по-своему.

Вместо того чтобы создавать отдельные массивы для каждого животного, вы объявляете массив или список типа Animal и кладёте туда кого угодно:

Animal[] animals = {
    new Dog(),
    new Cat(),
    new Cow(),
    new Parrot()
};

Теперь вы можете пройтись по этому массиву и вызвать makeSound() для каждого:

for (Animal animal : animals) {
    animal.makeSound();
}

Магия! Каждый объект сам знает, какой звук издавать, и вам не нужно писать кучу if-ов или switch-ов.

Пример с аналогией

Это как если бы вы дали команду «Голос!» группе животных, и каждое из них само решило, что делать: собака залает, кошка мяукнет, а корова — промычит. Вы не уточняете, кто есть кто, — просто вызываете один и тот же метод.

2. Практический пример: иерархия сотрудников

Давайте сделаем пример ближе к жизни (и к будущей работе в IT). Представим, что у нас есть компания с разными сотрудниками: менеджеры, разработчики, тестировщики. У каждого есть метод work(), но выполняется он по-разному.

Объявление базового класса

public class Employee {
    public void work() {
        System.out.println("Сотрудник работает...");
    }
}

Подклассы

public class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("Менеджер проводит совещание.");
    }
}

public class Developer extends Employee {
    @Override
    public void work() {
        System.out.println("Разработчик пишет код.");
    }
}

public class Tester extends Employee {
    @Override
    public void work() {
        System.out.println("Тестировщик ищет баги.");
    }
}

Использование массива/списка базового типа

public class CompanyDemo {
    public static void main(String[] args) {
        Employee[] team = {
            new Manager(),
            new Developer(),
            new Tester(),
            new Developer()
        };

        for (Employee e : team) {
            e.work(); // Вызовется "правильная" версия метода для каждого объекта
        }
    }
}

Результат выполнения:

Менеджер проводит совещание.
Разработчик пишет код.
Тестировщик ищет баги.
Разработчик пишет код.

В чём плюсы?

  • Вы не пишете кучу проверок типа «Если это Developer — делай то-то».
  • Добавить нового сотрудника (например, Designer) — просто создать новый класс и добавить его в массив.
  • Код, который использует массив сотрудников, не меняется вообще!

3. Преимущества полиморфизма: гибкость и расширяемость

Давайте представим, что в вашей компании появился новый тип сотрудника — Designer. Всё, что вам нужно сделать, — это создать новый класс:

public class Designer extends Employee {
    @Override
    public void work() {
        System.out.println("Дизайнер рисует макеты.");
    }
}

Теперь можно добавить дизайнера в команду:

Employee[] team = {
    new Manager(),
    new Developer(),
    new Tester(),
    new Designer()
};

Вуаля! Программа сразу начинает корректно работать с новым типом сотрудника, не меняя ни строчки в коде, который перебирает массив и вызывает work().

Это и есть расширяемость: ваш код легко адаптируется к новым типам объектов.

4. Ограничения полиморфизма: обратная сторона медали

К сожалению, у любой магии есть свои ограничения (и цена, как в любой RPG).

Доступны только методы базового класса

Когда вы работаете с переменной типа Employee, вы можете вызвать только те методы, которые объявлены в классе Employee. Если в классе Developer есть специальный метод writeCode(), вы не сможете вызвать его напрямую:

Employee e = new Developer();
// e.writeCode(); // Ошибка компиляции: такого метода нет в Employee!

Если очень хочется вызвать специфичный метод, придётся делать приведение типа. Но это крайний случай. Если вы часто приводите типы, возможно, стоит пересмотреть проектирование классов — базовый класс или интерфейс должен содержать нужный метод.

if (e instanceof Developer) {
    Developer dev = (Developer) e;
    dev.writeCode();
}

Но тогда вы теряете универсальность и элегантность, ради которой всё это затевалось. Поэтому старайтесь проектировать базовый класс так, чтобы в нём были только те методы, которые действительно нужны всем наследникам.

5. Практика: реализуем иерархию сотрудников

Давайте совместим приятное с полезным: напишем простое приложение, где есть несколько типов сотрудников, и используем полиморфизм для их обработки.

Шаг 1: Базовый класс и подклассы

// Employee.java
public class Employee {
    public void work() {
        System.out.println("Сотрудник работает...");
    }
}

// Manager.java
public class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("Менеджер проводит совещание.");
    }
}

// Developer.java
public class Developer extends Employee {
    @Override
    public void work() {
        System.out.println("Разработчик пишет код.");
    }
}

// Tester.java
public class Tester extends Employee {
    @Override
    public void work() {
        System.out.println("Тестировщик ищет баги.");
    }
}

Шаг 2: Главный класс

// CompanyDemo.java
public class CompanyDemo {
    public static void main(String[] args) {
        Employee[] team = {
            new Manager(),
            new Developer(),
            new Tester(),
            new Developer()
        };

        for (Employee e : team) {
            e.work();
        }
    }
}

Шаг 3: Добавим расширяемость

Допустим, через месяц в компании появляется новый сотрудник — дизайнер. Всё, что нужно:

public class Designer extends Employee {
    @Override
    public void work() {
        System.out.println("Дизайнер рисует макеты.");
    }
}

Всё, теперь можно добавить дизайнера в команду:

Employee[] team = {
    new Manager(),
    new Developer(),
    new Tester(),
    new Designer()
};

Итог

Весь основной код (CompanyDemo) остался неизменным! Это и есть сила полиморфизма.

6. Типичные ошибки при использовании полиморфизма

Ошибка №1: Ожидание доступа к специфичным методам через ссылку базового типа.
Очень часто новички пытаются вызвать специфичные методы подкласса через переменную типа суперкласса. Например:

Employee e = new Developer();
// e.writeCode(); // Ошибка! Такой метод не определён в Employee.

Чтобы вызвать специфичный метод, нужно привести тип, но тогда теряется универсальность.

Ошибка №2: Неиспользование аннотации @Override.
Если забыть аннотацию, можно случайно написать новый метод вместо переопределения (например, ошибиться в названии). Тогда полиморфизм просто не сработает, и будет вызвана версия из суперкласса.

Ошибка №3: Отсутствие общего интерфейса.
Если базовый класс не содержит нужного метода, полиморфизм невозможен. Например, если в Employee нет метода work(), то цикл по массиву сотрудников не сможет вызывать этот метод для всех.

Ошибка №4: Нарушение принципа открытости/закрытости.
Если для добавления нового типа сотрудника приходится менять код, который перебирает массив/список, — значит, вы не используете полиморфизм должным образом.

1
Задача
JAVA 25 SELF, 18 уровень, 3 лекция
Недоступна
Голоса цифровой энциклопедии животных
Голоса цифровой энциклопедии животных
1
Задача
JAVA 25 SELF, 18 уровень, 3 лекция
Недоступна
Корпоративная симфония: Полиморфизм в работе сотрудников
Корпоративная симфония: Полиморфизм в работе сотрудников
1
Задача
JAVA 25 SELF, 18 уровень, 3 лекция
Недоступна
Расширение команды: Добавление нового типа сотрудника
Расширение команды: Добавление нового типа сотрудника
1
Задача
JAVA 25 SELF, 18 уровень, 3 лекция
Недоступна
Динамичный офис: Расширяемость и универсальность полиморфизма
Динамичный офис: Расширяемость и универсальность полиморфизма
Комментарии (16)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Kidze Уровень 20
31 декабря 2025
Вы знаете что такое безумие?)
Ksanders Уровень 32
28 ноября 2025
Спасибо комментатором ниже - помогли использовать комбинации клавиш Alt-Enter, Ctrl-O, о таких вроде ранее в курсе не рассказывалось. Может сэкономить изрядное количество времени на копипаст. Опять же можно копировать методы из предыдущих уроков просто из папки в папку.
Ksanders Уровень 32
27 ноября 2025
Если на следующем уровне снова будут звуки животных - я точно в дурку!
ph0t0nchik Уровень 24
12 ноября 2025
Гав-гав! Мяу-мяу!
Ksanders Уровень 32
27 ноября 2025
Му́уууууууууу!
Mikeysoll Уровень 21
8 декабря 2025
11:11
I'll kick them all Уровень 5
24 сентября 2025
Блин, сколько еще задач на Alt-Enter, Ctrl-O, sout ctrl-c ctrl-v? Ну серьезно.
Anton Pohodin Уровень 26
7 октября 2025
А как же Аlt + Insert? Или только я в IntelliJ IDEA учусь здесь?
I'll kick them all Уровень 5
7 октября 2025
Насколько я помню, тут были однотипные задачи с написанным методом main, под который нужно было создавать классы, которые будут реализовывать интерфейсы, иметь поля, наследоваться и так далее. Alt-Insert хорошая команда для генерации equals/hashCode, getters/setters/constructors и т.д., но проще всего тут было нажаль Alt-Enter на ошибке - create class/interface, дальше на ошибке в конструкторе Alt-Enter - Generate constructor. Ну а Ctrl-O - переопределить методы. И да. Все комбинации из IDEA выше=)
Anton Pohodin Уровень 26
7 октября 2025
Ну это да - команды Alt + Enter и Ctrl + O действительно очень помогают, но только в том случае, если код пишется не с нуля. В реальных проектах, когда всё, что у вас есть это пустые классы и мэйн - от комбинации Alt + Insert будет намного больше пользы)
I'll kick them all Уровень 5
7 октября 2025
Так а комментарий к тому и был что все здесь однотипные задачи на применение Alt-Enter были. И из раздела в раздел - одни и те же. Animal, Worker и т.д.
Anton Pohodin Уровень 26
7 октября 2025
У меня были пробелы в знаниях о раннем и позднем связывании (полиморфизме), теперь их точно нет) но в целом вы правы. Надеюсь, после 20-го уровня будет поинтереснее.
I'll kick them all Уровень 5
7 октября 2025
Там станет в два раза меньше задач:( но сложность особо не вырастет. Старый курс более челенджевый
Anton Pohodin Уровень 26
7 октября 2025
Буду знать. Насколько я понимаю Java 25 SELF нацелен главным образом на новую платформу Java 25 и именно в этом курсе будут описаны все новые фишки текущей версии Java. В принципе я за этим и пришел сюда - за новыми фишками, да и знания по паттернам проектирования и интерфейсам подтянуть тоже не помешает. С C# переходить на Java для меня довольно легко, тем более что с появлением в Java новой API (IO) различия между этими двумя языками стали еще более призрачными :)
Ioanna Polyak Уровень 43
31 октября 2025
Если в старый курс вложили душу, то в остальные курсы вложили ..........................................(эту строчку заполните сами). У кого есть идеи как ее заполнить - лайк.
Ksanders Уровень 32
28 ноября 2025
К сожалению информация о новых фишках JAVA 25 в курсе очень сильно преувеличена, а вот полезные дополнительные материалы которые были в конце каждого уровня, видео и прочее убраны - так что я не уверен что это все пошло на пользу.