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 (скейтборд) має здібності рухатися та бути керованим людиною

18
Задача
Java Syntax Zero,  18 рівень8 лекція
Недоступна
Літати чи плавати?
Є 2 інтерфейси — Swimmable і Flyable, які вказують, чи вміє об'єкт відповідно плавати та/або літати. Реалізуй ці інтерфейси в класах Zeppelin (Дирижабль), Ship (Корабель) і JamesBondCar (Машина Джеймса Бонда) відповідно до їхніх можливостей. Пам'ятай: машина Джеймса Бонда вміє все.

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;
         крикун.голос();
      }
   }
}
А як подати їм команду?

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

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


18
Задача
Java Syntax Zero,  18 рівень8 лекція
Недоступна
Вілларібо і Віллабаджо
У містечку Вілларібо є струнний оркестр, а в містечку Віллабаджо — клавішний. Одного разу візки з музикантами із двох містечок зіткнулися на перехресті, і все змішалося в купу. Допоможи артистам розібрати свої інструменти. І, звичайно, після цього обидва оркестри мають дати концерт. Для цього: у ме

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


18
Задача
Java Syntax Zero,  18 рівень8 лекція
Недоступна
Дорожній рух
Класи Car і Bus реалізують інтерфейс Vehicle. Проте деякі методи цього інтерфейсу реалізовано в цих класах по-різному. Реалізуй ці методи як default у самому інтерфейсі Vehicle і видали їх із класів Car і Bus.
18
Задача
Java Syntax Zero,  18 рівень8 лекція
Недоступна
Хто летить?
Класи Eagle (Орел), Raven (Ворон) і Aircraft (Літак) реалізують інтерфейс Flyable, який містить дефолтну реалізацію методу int getMaxSpeed() і повертає значення 80. Це неправильна реалізація, тому що в дійсності максимальна швидкість Орла — 180 км/год, Ворона — 48, а літака — 1200. Тобі потрібно вид