1. Здібності
Аби краще зрозуміти переваги інтерфейсів і способи їх використання, слід поговорити про більш абстрактні речі.
Клас — це зазвичай модель певного об'єкта. А інтерфейс здебільшого описує не об'єкти, а їхні здібності або ролі.

Наприклад, такі речі, як машина, велосипед, мотоцикл і колесо найкраще подати у вигляді класів і об'єктів. А такі їхні здібності, як «можу їздити», «можу перевозити людей», «можу стояти», краще подати у вигляді інтерфейсів. Наведемо кілька прикладів:
Код | Опис |
---|---|
|
відповідає здібності рухатися |
|
відповідає здібності бути керованим |
|
відповідає здібності перевозити вантажі |
|
клас Wheel (колесо) має здібність рухатися |
|
клас Car (автомобіль) має здібності рухатися, бути керованим людиною та перевозити вантажі |
|
клас Skateboard (скейтборд) має здібності рухатися та бути керованим людиною |
2. Ролі
Інтерфейси значно спрощують програмістам життя. Дуже часто програми містять тисячі об'єктів, сотні класів і лише кілька десятків інтерфейсів — ролей. Ролей мало, а їх комбінацій, тобто класів, — дуже багато.
Сенс у тому, що вам не потрібно писати код для взаємодії всіх класів з усіма — достатньо взаємодіяти з їхніми ролями (інтерфейсами).
Уявіть, що ви дресируєте домашніх тварин, кожна з яких може мати кілька різних здібностей. І ви посперечалися із сусідом, чиї тварини голосніше кричать. Ви просто вибираєте всіх, хто має здатність «голос», і командуєте їм: «Голос!»
Вам все одно, що це за тварини та які інші здібності вони мають. Хоч потрійне сальто назад. У цей конкретний момент вас цікавить лише здібність голосно кричати. Отакий вигляд це має в коді:
Код | Опис |
---|---|
|
Здібність Звучання . Розуміє команду голос — має відповідний метод. |
|
Тварини, які мають таку характеристику
Для зручності ми надали класам українські імена. Таке допускається в Java, але є вкрай небажаним.
|
|
А як подати їм команду? |
Коли кількість класів у ваших програмах досягне кількох тисяч, ви вже не зможете обійтися без інтерфейсів. Замість опису взаємодії тисяч класів досить описати взаємодію десятків інтерфейсів — це суттєво спрощує життя.
А в поєднанні з поліморфізмом — це просто бомба.
3. Реалізація default
у методах інтерфейсів
Абстрактні класи можуть мати змінні й реалізацію методів, але множинне успадкування для них заборонено. Інтерфейси не можуть мати змінних і реалізації методів, але множинне успадкування для них дозволено.
Покажемо це у вигляді таблиці:
Здібність | Абстрактні класи | Інтерфейси |
---|---|---|
Змінні | ✔ | ✖ |
Реалізація методів | ✔ | ✖ |
Множинне успадкування | ✖ | ✔ |
Декому з програмістів дуже хотілося, щоб інтерфейси теж мали можливість реалізовувати методи. Можливість додати реалізацію методу не означає, що її завжди обов'язково додаватимуть. Хочеш — додавай, не хочеш — не додавай.
До того ж є проблеми із множинним успадкуванням — головним чином через змінні. У результаті вирішили — зробили. Починаючи з JDK 8 у Java з'явилася можливість додавати в інтерфейси методи з реалізацією.
Нова актуальна таблиця (для JDK 8 і вище):
Здібність | Абстрактні класи | Інтерфейси |
---|---|---|
Змінні | ✔ | ✖ |
Реалізація методів | ✔ | ✔ |
Множинне успадкування | ✖ | ✔ |
Тепер в абстрактних класах і в інтерфейсах можна оголошувати методи і з реалізацією, і без неї. І це чудова новина!
В абстрактних класах перед методами без реалізації потрібно додавати ключове слово abstract
, а перед методами з реалізацією нічого додавати не потрібно. А в інтерфейсах все навпаки: якщо метод не має реалізації, нічого додавати не потрібно, а якщо реалізація є, потрібно додати ключове слово default
.
Наведемо цю інформацію у вигляді таблички:
Здібність | Абстрактні класи | Інтерфейси |
---|---|---|
Методи без реалізації | abstract |
– |
Методи з реалізацією | – | default |
Проблема
За допомогою інтерфейсів із методами можна значно спростити ієрархію багатьох класів. Наприклад, абстрактні класи InputStream
і OutputStream
можна оголосити інтерфейсами. Це дасть змогу використовувати їх набагато частіше й значно зручніше.
Але у світі вже написано десятки мільйонів (мільярди?) Java-класів. І якщо почати змінювати стандартні бібліотеки, то є ризик, що щось може поламатися. Навіть усе! 😛
Щоб випадково не зламати працюючі програми й бібліотеки, було вирішено, що під час успадкування реалізація методів в інтерфейсах матиме найнижчий пріоритет.
Наприклад, якщо від інтерфейсу з методом успадкувати другий інтерфейс і оголосити в ньому той самий метод, але без реалізації, то реалізація з першого методу до класу не дійде. Приклад:
interface Pet
{
default void meow()
{
System.out.println("Няв");
}
}
interface Cat extends Pet
{
void meow(); // тут дефолтну реалізацію перекрито відсутністю реалізації
}
class Barsik implements Cat
{
}
Код не скомпілюється, тому що в класі Barsik
не реалізовано метод meow()
.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ