JavaRush /Курси /JAVA 25 SELF /Абстрактні класи та методи: синтаксис, приклади

Абстрактні класи та методи: синтаксис, приклади

JAVA 25 SELF
Рівень 19 , Лекція 1
Відкрита

1. Синтаксис абстрактного класу

Розберімося, що таке абстрактний клас у Java й навіщо він узагалі потрібен. Уявіть конструктор LEGO: маєте набір деталей (наприклад, «колеса», «кубики») та спеціальні елементи для конкретних моделей. Абстрактний клас — це узагальнена інструкція щодо роботи з деталями без опису складання конкретної моделі: кубики зчіплюються пазами, колеса кріпляться до осей, деталі можна нарощувати шарами. Абстрактний клас задає саме ці загальні правила й обовʼязкові кроки, але не розписує складання конкретної моделі. Конкретні моделі — це підкласи: вони беруть загальну інструкцію та заповнюють відсутні кроки.

У Java абстрактний клас — це клас, який не можна створити безпосередньо (не можна зробити new AbstractClass()), але від нього можна успадковуватися й реалізовувати його «нереалізовані» методи.

Абстрактні класи потрібні, коли:

  • У групи обʼєктів є спільна поведінка або стан, але частина логіки відрізняється.
  • Ви хочете реалізувати частину функціональності «за замовчуванням», а частину залишити на реалізацію нащадкам.
  • Ви хочете заборонити створення обʼєктів цього класу безпосередньо (наприклад, «Птах» як такий не існує самостійно, а от «Кіт» — існує).

Як оголосити абстрактний клас

Усе просто: перед словом class пишемо ключове слово abstract.

public abstract class Animal {
    // Поля (наприклад, імʼя тварини)
    protected String name;

    // Конструктор
    public Animal(String name) {
        this.name = name;
    }

    // Абстрактний метод — лише оголошення без реалізації!
    public abstract void makeSound();

    // Звичайний (реалізований) метод
    public void sleep() {
        System.out.println(name + " спить: Zzz...");
    }
}

Особливості:

  • Абстрактний клас може містити як реалізовані методи, так і абстрактні.
  • Абстрактний клас може містити поля, конструктори й навіть static-методи.
  • Не можна створити обʼєкт абстрактного класу безпосередньо:
  • Animal a = new Animal("Хтось"); // Помилка!

Як оголосити абстрактний метод

Абстрактний метод — це метод без тіла, тобто без фігурних дужок і коду всередині. Він оголошується ключовим словом abstract і обовʼязково закінчується крапкою з комою ;.

public abstract void makeSound();
  • Абстрактні методи можна оголошувати лише всередині абстрактного класу.
  • Клас, що успадковує абстрактний клас, зобовʼязаний реалізувати всі абстрактні методи, інакше він теж стає abstract.

2. Успадкування абстрактних класів: як це працює

Подивімося на конкретний приклад. Припустімо, що маємо абстрактний клас Animal з абстрактним методом makeSound(). Тепер створімо клас‑нащадок Dog, який реалізує цей метод:

public class Dog extends Animal {
    public Dog(String name) {
        super(name); // Виклик конструктора базового класу
    }

    @Override
    public void makeSound() {
        System.out.println(name + " гавкає: Гав-Гав!");
    }
}

І ще один клас‑нащадок:

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " нявчить: Няв!");
    }
}

Тепер можемо використати ці класи в програмі:

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("Рекс");
        Animal cat = new Cat("Мурка");

        dog.makeSound(); // Рекс гавкає: Гав-Гав!
        cat.makeSound(); // Мурка нявчить: Няв!

        dog.sleep(); // Рекс спить: Zzz...
        cat.sleep(); // Мурка спить: Zzz...
    }
}

Зверніть увагу:
Можемо оголошувати змінні типу Animal, але створювати обʼєкти — лише конкретних (не абстрактних) нащадків.

Схема: як це виглядає


.         Animal (abstract)
            /         \
         Dog         Cat
 (реалізує makeSound) (реалізує makeSound)

3. Коли використовувати абстрактний клас, а коли інтерфейс?

Це одне з найпопулярніших запитань на співбесідах — і недарма! Розберімося:

  • Абстрактний клас — коли в обʼєктів є спільний стан (наприклад, поля), спільна логіка (методи з реалізацією), і ви хочете дати «скелет» поведінки з можливістю доопрацювання.
  • Інтерфейс — коли ви хочете задати лише набір методів (контракт), без реалізації та стану. Починаючи з Java 8, інтерфейси отримали default/static-методи, але все одно інтерфейс — про «що має вміти обʼєкт», а не «як він це робить».

Приклад з життя:
«Птах» — абстрактний клас: у всіх птахів є дзьоб, крила, і вони можуть літати (але по‑різному).
«Літаючий» — інтерфейс: не лише птахи вміють літати, а й літаки та супергерої! Літають усі по‑різному, та головне — вони це вміють.

4. Практичні приклади

Приклад 1: Абстрактний клас із частковою реалізацією

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

public abstract class Transport {
    protected String name;
    protected int speed;

    public Transport(String name, int speed) {
        this.name = name;
        this.speed = speed;
    }

    // Абстрактний метод — реалізація в нащадках
    public abstract void move();

    // Реалізований метод
    public void stop() {
        System.out.println(name + " зупинився.");
    }
}

public class Car extends Transport {
    public Car(String name, int speed) {
        super(name, speed);
    }

    @Override
    public void move() {
        System.out.println(name + " їде дорогою зі швидкістю " + speed + " км/год.");
    }
}

public class Bicycle extends Transport {
    public Bicycle(String name, int speed) {
        super(name, speed);
    }

    @Override
    public void move() {
        System.out.println(name + " крутить педалі зі швидкістю " + speed + " км/год.");
    }
}

Використання:

Transport car = new Car("Toyota", 120);
Transport bike = new Bicycle("Stels", 25);

car.move(); // Toyota їде дорогою зі швидкістю 120 км/год.
bike.move(); // Stels крутить педалі зі швидкістю 25 км/год.

car.stop(); // Toyota зупинився.
bike.stop(); // Stels зупинився.

Приклад 2: Абстрактний метод area()

public abstract class Shape {
    public abstract double area();
}

public class Circle extends Shape {
    private double radius;
    public Circle(double radius) {
        this.radius = radius;
    }
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

public class Rectangle extends Shape {
    private double width, height;
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    @Override
    public double area() {
        return width * height;
    }
}

Використання:

Shape c = new Circle(3);
Shape r = new Rectangle(4, 5);

System.out.println("Площа кола: " + c.area());
System.out.println("Площа прямокутника: " + r.area());

5. Особливості та нюанси абстрактних класів

  • Абстрактний клас може містити будь‑які модифікатори доступу: public, protected, private (наприклад, для полів).
  • Можна оголосити абстрактний клас без абстрактних методів. Це буває корисно, якщо ви просто хочете заборонити створення екземплярів базового класу.
  • Якщо клас успадковує абстрактний клас, але не реалізує всі абстрактні методи, його також слід оголошувати як abstract.
  • Абстрактний клас може мати конструктори. Вони викликаються під час створення обʼєкта‑нащадка (через super(...)).
  • Абстрактні методи не можуть бути private (інакше їх неможливо перевизначити в нащадку).
  • Абстрактні методи не можуть бути static (статичні методи не перевизначаються) і не можуть бути final (адже final забороняє перевизначення).
  • Абстрактний клас може реалізовувати інтерфейси, але не зобовʼязаний реалізовувати їхні методи — це можуть зробити нащадки.

Таблиця: порівняння абстрактного класу та інтерфейсу

Абстрактний клас Інтерфейс
Ключове слово
abstract class
interface
Може містити поля Так (будь‑які) Починаючи з Java 8 — лише static/final
Методи з реалізацією Так Починаючи з Java 8 — default/static
Абстрактні методи Так Так
Множинне наслідування Ні Так (можна реалізувати багато інтерфейсів)
Конструктори Так Ні
Можна створити обʼєкт Ні Ні

6. Типові помилки під час роботи з абстрактними класами та методами

Помилка № 1: спроба створити екземпляр абстрактного класу.
Якщо ви напишете new Animal("Хтось"), компілятор одразу повідомить, що абстрактні класи для цього не призначені. Памʼятайте: абстракція — це «скелет», а не «живий організм».

Помилка № 2: забули реалізувати всі абстрактні методи в нащадку.
Якщо ваш клас не реалізує хоча б один абстрактний метод базового класу, його слід оголосити як abstract, інакше отримаєте помилку компіляції.

Помилка № 3: оголосили абстрактний метод поза абстрактним класом.
У Java не можна оголосити абстрактний метод у звичайному (неабстрактному) класі — компілятор одразу повідомить про помилку.

Помилка № 4: спроба зробити абстрактний метод private або static.
Абстрактні методи не можуть бути private (їх неможливо перевизначити) і не можуть бути static (статичні методи не перевизначаються). Також вони не можуть бути final, адже final забороняє перевизначення.

Помилка № 5: забули про модифікатор доступу для абстрактного методу.
Якщо ви явно не вкажете модифікатор, метод матиме пакетну видимість (package‑private), що інколи не те, що ви хотіли отримати.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ