Модульні уроки (2/2)
Поліморфізм і абстрактні класи
Поліморфізм і абстрактні класи — це передові концепції об’єктно-орієнтованого програмування, які дозволяють нам писати гнучкий, розширюваний код незалежно від конкретних реалізацій.
Поліморфізм
Термін поліморфізм (багато форм) відноситься до здатності розглядати об’єкти різних класів так, ніби вони належать до спільного типу. У 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");
}
}Завдяки поліморфізму ми можемо це зробити:
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()). Він служить «частковим шаблоном» для інших класів.
Методи реферату
Абстрактний клас може містити абстрактні методи: методи, оголошені без тіла (без фігурних дужок і без коду), що закінчуються крапкою з комою. Неабстрактні підкласи необхідні для реалізації всіх успадкованих абстрактних методів.
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) перевіряє фактичний об’єкт у пам’яті та викликає реалізацію методу, визначену в класі цього об’єкта.
Абстрактні класи та відсутня реалізація
Якщо підклас успадковує від абстрактного класу, він має два варіанти:
- Реалізуйте всі абстрактні методи: у цьому випадку підклас може бути звичайним (конкретним) класом і може бути створений.
- Оголосити себе абстрактним: якщо підклас не забезпечує реалізацію для всіх успадкованих абстрактних методів, він також повинен бути оголошений за допомогою ключового слова
abstract.
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
}Спробуйте самі
Оголошіть змінну s типу Shape і призначте їй новий об’єкт Circle за допомогою поліморфізму.
Показати підказку
Напишіть `Shape s = new Circle();`, щоб використовувати базовий тип як тип посилання.
Рішення доступне після 3 спроб
Зробіть клас Shape абстрактним і додайте абстрактний метод double getArea(). Потім завершіть Square так, щоб він розширив Shape і реалізував getArea() повертає side * side.
Показати підказку
Оголошіть `public abstract double getArea();` у Shape. У Square додайте `@Override public double getArea() { return side * side; }`.
Рішення доступне після 3 спроб
Оголошіть у основному методі масив типу 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 спроб