Перейти до основного вмісту
Модуль 3 · Урок 2 із 26/14 у курсі~15 min
Модульні уроки (2/2)

Поліморфізм і абстрактні класи

Поліморфізм і абстрактні класи — це передові концепції об’єктно-орієнтованого програмування, які дозволяють нам писати гнучкий, розширюваний код незалежно від конкретних реалізацій.

Поліморфізм

Термін поліморфізм (багато форм) відноситься до здатності розглядати об’єкти різних класів так, ніби вони належать до спільного типу. У Java посилальна змінна суперкласу може зберігати посилання на об’єкт будь-якого з його підкласів.

Java
class Animal {
    public void makeSound() {
        System.out.println("Verso...");
    }
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("Woof");
    }
}

class Cat extends Animal {
    public void makeSound() {
        System.out.println("Miao");
    }
}

Завдяки поліморфізму ми можемо це зробити:

Java
Animal myAnimal1 = new Dog(); // Polymorphism
Animal myAnimal2 = new Cat(); // Polymorphism

myAnimal1.makeSound(); // Executes Dog's method (Woof)
myAnimal2.makeSound(); // Executes Cat's method (Miao)

Рішення про те, який метод викликати, приймається під час виконання (пізнє зв’язування чи динамічна відправка) на основі фактичного об’єкта, а не типу посилальної змінної.

Абстрактні класи (abstract)

Абстрактний клас – це клас, позначений ключовим словом abstract, який не можна створити безпосередньо (ви не можете зробити new MyAbstractClass()). Він служить «частковим шаблоном» для інших класів.

Методи реферату

Абстрактний клас може містити абстрактні методи: методи, оголошені без тіла (без фігурних дужок і без коду), що закінчуються крапкою з комою. Неабстрактні підкласи необхідні для реалізації всіх успадкованих абстрактних методів.

Java
abstract class Shape {
    String color;

    // Abstract method (no body)
    public abstract double getArea();
}

class Circle extends Shape {
    double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    // Required to implement getArea
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

Динамічне зв'язування / Пізнє зв'язування

Як Java знає, який метод виконати під час виконання? Цей процес відомий як пізнє зв’язування (або динамічне зв’язування). На відміну від перевантаження (яке вирішується під час компіляції), компілятор не знає, який саме метод буде виконано. Замість цього він генерує загальну інструкцію виклику. Під час виконання віртуальна машина Java (JVM) перевіряє фактичний об’єкт у пам’яті та викликає реалізацію методу, визначену в класі цього об’єкта.

Абстрактні класи та відсутня реалізація

Якщо підклас успадковує від абстрактного класу, він має два варіанти:

  1. Реалізуйте всі абстрактні методи: у цьому випадку підклас може бути звичайним (конкретним) класом і може бути створений.
  2. Оголосити себе абстрактним: якщо підклас не забезпечує реалізацію для всіх успадкованих абстрактних методів, він також повинен бути оголошений за допомогою ключового слова abstract.
Java
abstract class Animal {
    public abstract void makeSound();
}

// This class MUST be abstract because it does not implement makeSound()
abstract class Canine extends Animal {
    // Inherits makeSound() but does not implement it
}

Спробуйте самі

вправи#java.m3.l2.e1
Спроби: 0Завантаження…

Оголошіть змінну s типу Shape і призначте їй новий об’єкт Circle за допомогою поліморфізму.

Завантаження редактора…
Показати підказку

Напишіть `Shape s = new Circle();`, щоб використовувати базовий тип як тип посилання.

Рішення доступне після 3 спроб

вправи#java.m3.l2.e2
Спроби: 0Завантаження…

Зробіть клас Shape абстрактним і додайте абстрактний метод double getArea(). Потім завершіть Square так, щоб він розширив Shape і реалізував getArea() повертає side * side.

Завантаження редактора…
Показати підказку

Оголошіть `public abstract double getArea();` у Shape. У Square додайте `@Override public double getArea() { return side * side; }`.

Рішення доступне після 3 спроб

вправи#java.m3.l2.e3
Спроби: 0Завантаження…

Оголошіть у основному методі масив типу Shape[], що містить об’єкт Circle з радіусом 2,0 і об’єкт Square зі стороною 3,0. Потім використовуйте цикл (for або for-each), щоб надрукувати область кожної фігури, викликавши метод getArea().

Завантаження редактора…
Показати підказку

Оголошіть масив за допомогою `Shape[] shapes = { new Circle(2.0), new Square(3.0) };` і прокрутіть його за допомогою `for (Shape s : shapes)`, друкуючи `s.getArea()`.

Рішення доступне після 3 спроб