JavaRush /Курси /Java Syntax Zero /Сутність інтерфейсів

Сутність інтерфейсів

Java Syntax Zero
Рівень 18 , Лекція 8
Відкрита

1. Здібності

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

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

Сутність інтерфейсів

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

Код Опис
interface Movable
{
   void move(String newAddress);
}
відповідає здібності рухатися
interface Driveable
{
   void drive(Driver driver);
}
відповідає здібності бути керованим
interface Transport
{
   void addStuff(Object stuff);
   Object removeStuff();
}
відповідає здібності перевозити вантажі
class Wheel implements Movable
{
   ...
}
клас Wheel (колесо) має здібність рухатися
class Car implements Movable, Driveable, Transport
{
   ...
}
клас Car (автомобіль) має здібності рухатися, бути керованим людиною та перевозити вантажі
class Skateboard implements Movable, Driveable
{
   ...
}
клас Skateboard (скейтборд) має здібності рухатися та бути керованим людиною


2. Ролі

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

Сенс у тому, що вам не потрібно писати код для взаємодії всіх класів з усіма — достатньо взаємодіяти з їхніми ролями (інтерфейсами).

Уявіть, що ви дресируєте домашніх тварин, кожна з яких може мати кілька різних здібностей. І ви посперечалися із сусідом, чиї тварини голосніше кричать. Ви просто вибираєте всіх, хто має здатність «голос», і командуєте їм: «Голос!»

Вам все одно, що це за тварини та які інші здібності вони мають. Хоч потрійне сальто назад. У цей конкретний момент вас цікавить лише здібність голосно кричати. Отакий вигляд це має в коді:

Код Опис
interface Звучання
{
   void голос();
}
Здібність Звучання. Розуміє команду голос — має відповідний метод.
class Кіт implements Звучання
{
   void голос()
   {
      println("НЯВ");
   }
}

class Собака implements Звучання
{
   void голос()
   {
      println("ГАВ");
   }
}

class Рибка
{
   ...
}
Тварини, які мають таку характеристику

Для зручності ми надали класам українські імена. Таке допускається в Java, але є вкрай небажаним.













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

public static void main(String[] args)
{
   // додаємо всіх тварин до списку
   ArrayList pets = new ArrayList();
   pets.add(new Кіт());
   pets.add(new Собака());
   pets.add(new Рибка());

   // кричати, якщо є така здібність
   for(Object pet: pets)
   {
      if (pet instanceof Звучання)
      {
         Звучання крикун = (Звучання) pet;
         крикун.голос();
      }
   }
}
А як подати їм команду?

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

А в поєднанні з поліморфізмом — це просто бомба.



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().


Коментарі (9)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
IronMan57 Рівень 28
17 січня 2025
Чому б в останніх двох задачах не залишити в інтерфейсах дефолтні реалізації методів? Все одно "під час успадкування реалізація методів в інтерфейсах матиме найнижчий пріоритет." На мій погляд, можна було б залишити, наприклад у інтерфейсі Vehicle щось на зразок:

    default void move() {
        System.out.println("Їду.");
    }
а в класах Car і Bus, залишити реалізації, які специфічні саме для цих класів. Тоді, у випадку, коли б додавався якийсь новий клас, що також реалізує інтерфейс Vehicle, у нього відразу б з'являлась якась можливість повідомити про свій рух. А на другому етапі можна б було вже у клас додати свою специфічну реалізацію. Те ж саме з інтерфейсом Flyable. Звичайно ж, все залежить від сутності об'єктів, які моделюються цими класами. Майбуть для запуску ядерного реактора дефолтний метод не найкраще рішення.
Peace The Ball Рівень 32
15 листопада 2022
Товариство, а чи є тут ще хто небудь хто пам'ятає Віллрібо і Віллабаджо? Чи то я один такий старий надумав Джаву вчити ? 🤣
19 листопада 2022
Є і ті що вміють факсом користуватися! 🙂
Anonymous #696530 Рівень 19
16 грудня 2022
Та є.. хоч і хз що з того вийде ))
Oleksandr Рівень 23
4 лютого 2023
+1. Є.....
Василь Рівень 1
24 жовтня 2023
37 зараз, перший раз познайомився з Java на початку 2020 року, на карантині
Olexandr Рівень 47
4 лютого 2024
42 зараз, не таке ще пам'ятаю))))) PS доречі - динозаврів я не застав🤣
Андрии Бумер Рівень 29
3 жовтня 2024
Звісно) до фака додам що є ті хто слухали плеєри на касетах, і в кого дома був телефон з дисковим набором і перший пентіум))
IronMan57 Рівень 28
17 січня 2025
Молодь. Коли я ходив у школу, у нас на все місто (райцентр) було два комп'ютери у відділі держстатистики, а перші уроки програмування у школі були на програмованих калькуляторах.