JavaRush /Курси /JAVA 25 SELF /Відмінності інтерфейсів від абстрактних класів

Відмінності інтерфейсів від абстрактних класів

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

1. Абстрактний клас: пригадаємо основи

Перш ніж перейти до порівняння, згадаємо, що таке абстрактний клас.

Абстрактний клас — це клас, який не можна створити безпосередньо (не можна написати new Animal()), але він може містити як звичайні (з реалізацією), так і абстрактні (без реалізації) методи. Абстрактний клас часто використовують як основу для інших класів, які наслідують його поведінку та/або зобовʼязані реалізувати деякі методи.

Наприклад, якщо у нашому застосунку є різні види транспорту, можна створити абстрактний клас Transport:

public abstract class Transport {
    private String model;

    public Transport(String model) {
        this.model = model;
    }

    public String getModel() {
        return model;
    }

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

    // Звичайний метод — реалізація є
    public void printInfo() {
        System.out.println("Модель транспорту: " + model);
    }
}

Особливості абстрактного класу:

  • Може містити поля (стан).
  • Може містити реалізовані методи.
  • Може містити абстрактні методи (обов’язкові до реалізації в нащадках).
  • Не можна створити екземпляр безпосередньо.
  • Використовується для спільної поведінки та стану.

2. Інтерфейс: пригадаємо основи

Інтерфейс — це набір методів, які має реалізувати клас. Інтерфейс не описує стан (не може мати звичайних полів, лише константи) і не містив реалізацій методів до Java 8. Інтерфейс — це чистий контракт: «Якщо ви мене реалізуєте, ви зобовʼязані вміти робити ось це».

Приклад інтерфейсу:

public interface Movable {
    void move(int x, int y);
}

Особливості інтерфейсу:

  • Не містить стану (лише public static final константи).
  • До Java 8 — лише абстрактні методи (починаючи з Java 8, зʼявилися default- і static-методи, але про них пізніше).
  • Методи за замовчуванням завжди public abstract.
  • Клас може реалізовувати кілька інтерфейсів.
  • Використовується для опису можливостей, «що вміє робити» клас.

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

Час порівняти ці два інструменти віч-на-віч! Ось наочна таблиця:

Особливість Абстрактний клас Інтерфейс
Синтаксис
abstract class
interface
Можна створювати екземпляр? Ні Ні
Може містити звичайні методи? Так До Java 8 — ні, з Java 8 — лише default/static
Може містити абстрактні методи? Так Так (усі методи до Java 8 — абстрактні)
Може містити поля (стан)? Так (будь-які поля) Лише public static final (константи)
Може містити конструктори? Так Ні
Наслідування Можна наслідувати лише один клас Можна реалізувати кілька інтерфейсів
Модифікатори методів Будь-які (public, protected, private) Методи за замовчуванням public abstract. Починаючи з Java 9, можна додавати private методи для використання всередині інтерфейсу.
Наслідування через
extends
implements
Для чого зазвичай використовується Спільна реалізація та стан Опис можливостей і ролей
Приклади з JDK
AbstractList, AbstractMap
Comparable, Runnable

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

Використовуйте інтерфейс, коли:

  • Ви хочете описати «що вміє робити» клас, не переймаючись тим, як він це робить.
  • Вам потрібно, щоб клас міг реалізувати кілька незалежних можливостей.
  • Приклад: Comparable (можна порівнювати), Serializable (можна серіалізувати), Runnable (можна запускати у потоці).

Використовуйте абстрактний клас, коли:

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

Життєві аналогії

  • Інтерфейс — це як «водійські права»: якщо вони у вас є, ви можете керувати автомобілем, але ніхто не каже, на якій саме машині і як саме ви це робите.
  • Абстрактний клас — це як «загальне креслення автомобіля»: у всіх машин є кермо, педалі, двигун, але кожна марка реалізує деталі по-своєму.

5. Приклади зі стандартної бібліотеки Java

Інтерфейс: Comparable

public interface Comparable<T> {
    int compareTo(T o);
}

Будь-який клас, який реалізує цей інтерфейс, зобовʼязаний реалізувати метод compareTo. Наприклад, String, Integer, LocalDate та багато інших.

Абстрактний клас: AbstractList

public abstract class AbstractList<E> implements List<E> {
    // Реалізація деяких методів List за замовчуванням
    // Деякі методи залишено абстрактними
}

AbstractList уже реалізує частину поведінки колекцій (наприклад, методи додавання/видалення), але залишає деякі методи абстрактними, щоб нащадки могли реалізувати їх по-своєму.

6. Приклади коду: порівняння на практиці

Інтерфейс

Створимо інтерфейс і клас, який його реалізує.

public interface Printable {
    void print();
}

public class Document implements Printable {
    @Override
    public void print() {
        System.out.println("Друкую документ...");
    }
}

Абстрактний клас

Тепер абстрактний клас і його нащадок.

public abstract class Machine {
    public void turnOn() {
        System.out.println("Машина увімкнена.");
    }

    public abstract void work();
}

public class Printer extends Machine {
    @Override
    public void work() {
        System.out.println("Принтер друкує...");
    }
}

Клас реалізує обидва: і інтерфейс, і абстрактний клас

public class SmartPrinter extends Machine implements Printable {
    @Override
    public void work() {
        System.out.println("Розумний принтер працює...");
    }

    @Override
    public void print() {
        System.out.println("Розумний принтер друкує...");
    }
}

7. Множинна реалізація інтерфейсів: чому це зручно

У Java клас може наслідувати лише один клас (абстрактний або звичайний), але реалізовувати скільки завгодно інтерфейсів! Це дозволяє створювати гнучкі, розширювані архітектури.

public interface Scannable {
    void scan();
}

public class MultiFunctionPrinter extends Machine implements Printable, Scannable {
    @Override
    public void work() {
        System.out.println("БФП працює...");
    }

    @Override
    public void print() {
        System.out.println("БФП друкує...");
    }

    @Override
    public void scan() {
        System.out.println("БФП сканує...");
    }
}

Коли що обирати?

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

8. Типові помилки та підводні камені

Помилка № 1: намагаєтеся наслідувати кілька класів — Java цього не дозволить!
Клас може наслідувати лише один клас, але реалізовувати багато інтерфейсів. Наприклад, class A extends B, C — помилка, а от class A extends B implements X, Y, Z — будь ласка.

Помилка № 2: плутаєте поля інтерфейсу та класу.
В інтерфейсі можна оголошувати лише константи (public static final). Не можна оголосити звичайний стан, наприклад, private int count; — компілятор одразу вас зупинить.

Помилка № 3: не реалізували всі методи інтерфейсу.
Якщо клас не реалізує бодай один метод інтерфейсу — його слід оголосити як abstract, інакше компілятор видасть помилку.

Помилка № 4: намагаєтеся створити екземпляр інтерфейсу або абстрактного класу.
Обидва ці типи — «напівфабрикати». Їх можна лише наслідувати/реалізовувати, але не можна створити безпосередньо:

Printable p = new Printable(); // Помилка!
Machine m = new Machine();     // Помилка!

Помилка № 5: думаєте, що інтерфейс може мати конструктор.
Інтерфейси не можуть мати конструкторів, оскільки вони не описують стан обʼєктів. Це можливо лише у класів (звичайних і абстрактних).

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