10 июля 2022

☕ Учебник по Java: cтатический и динамический полиморфизм

Веб-разработчик, фрилансер... Пишу об ИТ и смежных технологиях.
В статье разберемся с одной из ключевых концепций объектно-ориентированного программирования — полиморфизмом — и посмотрим, как она реализована в Java.
☕ Учебник по Java: cтатический и динамический полиморфизм

Хочешь уверенно проходить IT-интервью?

Готовься к IT-собеседованиям уверенно с AI-тренажёром T1!

Мы понимаем, как сложно подготовиться: стресс, алгоритмы, вопросы, от которых голова идёт кругом. Но с AI тренажёром всё гораздо проще.

💡 Почему Т1 тренажёр — это мастхэв?

  • Получишь настоящую обратную связь: где затык, что подтянуть и как стать лучше
  • Научишься не только решать задачи, но и объяснять своё решение так, чтобы интервьюер сказал: "Вау!".
  • Освоишь все этапы собеседования, от вопросов по алгоритмам до диалога о твоих целях.

Зачем листать миллион туториалов? Просто зайди в Т1 тренажёр, потренируйся и уверенно удиви интервьюеров. Мы не обещаем лёгкой прогулки, но обещаем, что будешь готов!

Реклама. ООО «Смарт Гико», ИНН 7743264341. Erid 2VtzqwP8vqy


Что такое Полиморфизм?

Слово «полиморфизм» произошло от двух греческих слов: «Poly» означающего «многочисленный» и «Morph» — форма. Если перевести дословно – бесчисленное множество форм. Живые примеры этого явления можно встретить в земной коре, среди животных и рептилий, а также в других областях науки. Но речь сегодня не об этом, а об основной парадигме ООП, применяющейся во многих языках программирования.

Что такое полиморфизм в программировании?

Полиморфизм в ООП подразумевает собой особенность, при которой одно и то же действие выполняется разными способами. Или, проще говоря, такая концепция позволяет выполнять несколько реализаций одной и той же сущности.

Чаще всего она возникает при наличии другой парадигмы ООП — наследования, т. е. когда у нас существует множество классов, связанных друг с другом. Наследование позволяет одному классу приобретать свойства и атрибуты другого, а полиморфизм использует унаследованные свойства для выполнения различных задач.

Примеры из жизни

Чтобы лучше понять принцип парадигмы, попробуем объяснить это с помощью нескольких простых примеров.

Возьмем нас с вами или если совсем обобщенно — человека. Он, в зависимости от различных обстоятельств, может вести себя по-разному. Например, женщина может быть и матерью, и дочерью, и сестрой, и другом одновременно и в разных ситуациях ее действия будут радикально отличаться.

А еще в организме человека есть разные органы и у каждого из них есть своя функция: сердце отвечает за кровоток, легкие за дыхание, мозг за когнитивную деятельность. То есть, у нас есть стандартная функция, работающая по-разному в зависимости от органа тела. Теперь перейдем конкретно к Java.

☕ Подтянуть свои знания по Java вы можете на нашем телеграм-канале «Библиотека Java для собеса»

Полиморфизм в Java

Что мы должны понимать про принцип действия рассматриваемой концепции? Ну во-первых, все то, что содержит или обрабатывает значения различных типов, когда идет компиляция или выполняется программа — является полиморфным, например:

  • любая переменная, которой присваивается значение другого типа;
  • любой объект, обладающий свойствами, изменяющими тип данных присвоенного ему значения;
  • любая функция, принимающая аргументы различных типов.

Рассмотрим небольшой пример по реализации полиморфизма на Java:

У суперкласса под названием Forms есть метод shapearea() и классы-потомки Triang и Circ. Каждый из них имеет свой способ подсчета площади. С помощью рассматриваемой парадигмы потомки пользуются методом родителя shapearea(), чтобы найти формулу для расчета своей площади.

        class Forms {
  public void shapearea() {
    System.out.println("Формулы:");
  }
}
class Triang extends Forms{
  public void shapearea() {
    System.out.println("Sтреугольника: ½ * основания * высоту");
  }
}
class Circ extends Forms{
  public void shapearea() {
    System.out.println("Sкруга: 3,14 * радиус * радиус");
  }
}
class Main {
  public static void main(String[] args) {
   Forms xForms = new Forms);  // создание объекта Forms
   Forms xTriang= new Triang();  //  создание объекта Triang
   Forms xCirc = new Circ();  // создание объекта Circ
    xForms.shapearea();
    xTriang.shapearea();
    xForms.shapearea();
    xCirc.shapearea();
  }
}

    

Вывод:

        Формула: площадь треугольника: ½ * основания * высоту
Формула: площадь круга: 3,14 * радиус * радиус
    
🧩☕ Интересные задачи по Java для практики можно найти на нашем телеграм-канале «Библиотека задач по Java»

Типы полиморфизма

Два варианта реализации полиморфизма в Java:

  1. Overloading – перегрузка метода
  2. Overriding – переопределение метода

При перегрузке метода мы в одном классе создаем нескольких методов с одинаковым названием, но разным функционалом, например:

        class Forms{
  public void shapearea()) {
    System.out.println("Площади фигур:");
  }
public void shapearea(int r) {
    System.out.println("Sкруга = "+3.14*r*r);
  }
public void shapearea(double b, double h) {
    System.out.println("Sтреугольника ="+0.5*b*h);
  }
public void shapearea(int l, int b) {
    System.out.println("Sпрямоугольника ="+l*b);
  }
}
 
class Main {
  public static void main(String[] args) {
   Forms xForms = new Forms();  
     
    xForms.shapearea();
    xForms.shapearea(3);
    xForms.shapearea(2.5, 2.0);
    xForms.shapearea(4,7);
     
  }
}

    

Вывод:

        Площади фигур:
Sкруга = 28.26
Sтреугольника = 5
Sпрямоугольника = 28
    

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

        class Vehicles{  
  // определение метода
  void drive(){
System.out.println("Управлять транспортным средством");}  
}  
//создаем дочерний класс
class Cars extends Vehicles{  
  //определяем одноименный метод
  void drive(){
System.out.println("Управлять автомобилем");
}  
  
  public static void main(String args[]){  
  Cars model= new Cars(); //создание нового объекта
  model.drive(); //вызов переопределенного метода
  }  
} 

    

Выведет:

        Управлять автомобилем
    

Статический и динамический полиморфизм

При статическом варианте развития событий метод можно вызывать при компиляции кода, происходит это при помощи рассмотренной нами ранее концепции — перегрузки методов. Говоря проще, у них будет одинаковое название, но разная функциональная начинка (тип возвращаемых данных, свойств и т. д.). В таком случае Java позволяет пользователю свободно определять функциям идентичные названия, если они будут отличны по типу и параметрам, например:

        public class Add {
  void sum(int x, int y) {
    int z = x + y;
    System.out.println(“Сумма двух чисел: ”+z);
  }
  void sum(int x, int y, int i) {
    int z = x + y + i;
    System.out.println(“Сумма трех чисел: ”+z);
  }
  public static void main(String[] args) {
    Add myAdd = new Add();
    myAdd.sum(5, 11);
    myAdd.sum(1, 8, 11);
  }
}
    

Вывод программы:

        Сумма двух чисел: 16
Сумма трех чисел: 20
    

При динамическом полиморфизме вызвать переопределеный метод можно при выполнении программы. Скопировать метод родительского класса и обозначить его в дочернем можно с помощью ссылочной переменной родительского класса, при этом вызванный метод будет определяться по объекту, на который она ссылается. Такую операцию еще называют Upcasting, например:

Создадим один родительский класс Звери и три подкласса: травоядные, плотоядные и всеядные. В этом случае классы-потомки расширили родителя и переопределили его метод eat().

        class Beast {
  void eat() {
    System.out.println("Животные питаются:");
    }
  }
  class herbivorous extends Beast {
    void eat() {
      System.out.println("Травоядные едят растения");
    }
  }
  class omnivorous extends Beast {
    void eat() {
      System.out.println("Всеядные едят растения и мясо");
    }
  }
  class carnivorous extends Beast {
    void eat() {
      System.out.println("Хищники едят только мясо");
    }
  }
  class main {
    public static void main(String args[]) {
      Beast X = new Beast();
      Beast herb = new herbivorous();
      Beast omni = new omnivorous();
      Beast carn = new carnivorous();
      X.eat();
      herb.eat();
      omni.eat();
      carn.eat();

    }
  }
    

Вывод:

        Животные питаются:
Травоядные едят растения
Всеядные едят растения и мясо
Хищники едят мясо
    

Преимущества и недостатки полиморфизма

  1. Предоставляет возможность повторного использования кода. Реализованные классы можно многократно использовать повторно. Кроме того, это экономит много времени разработчику, ведь при этом появляется возможность поменять что-то в программе, не трогая исходный код.
  2. Одна переменная может использоваться для хранения нескольких значений данных. Значение переменной в дочернем классе, наследуемой от родительского, может быть изменено без изменения родительской переменной.
  3. Легче отлаживать код, когда его не так много.

Помимо преимуществ, у рассматриваемой парадигмы есть еще и несколько недостатков:

  1. Полиморфизм не так просто реализовать на деле.
  2. Такой подход снижает читаемость кода.
  3. Может вызывать серьезные проблемы с производительностью в режиме реального времени.
***

Мы надеемся, что у вас сложилось правильное общее представление о полиморфизме в Java и о том, как его использовать. С более подробной информации по теме можно ознакомиться на официальном сайте Oracle.

Материалы по теме

Комментарии

ВАКАНСИИ

Добавить вакансию
Hotel Search Team Lead (Golang)
по итогам собеседования
Golang-разработчик
Пермь, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ