1. Знайомство з інтерфейсами

Сьогодні у вас справжній день знань. Ще одна нова й цікава тема — інтерфейси.

Інтерфейс — це дитя Абстракції та Поліморфізму. Інтерфейс дуже нагадує абстрактний клас, який має лише абстрактні методи. Він оголошується так само, як і клас, тільки використовується ключове слово interface.

interface Котячі
{
   void мурчати();
   void нявкати();
   void гарчати();
}

Декілька корисних фактів про інтерфейси:

1. Оголошення інтерфейсу

interface Drawable
{
   void draw();
}

interface HasValue
{
   int getValue();
}
  1. Замість слова class пишемо interface.
  2. Містить лише абстрактні методи (слово abstract писати не потрібно)
  3. Усі методи інтерфейсів — public
2. Успадкування інтерфейсів

Інтерфейс може успадковуватися тільки від інтерфейсів. Натомість може мати багато батьків. Про це кажуть, що в Java підтримується множинне успадкування інтерфейсів. Приклади:

interface Element extends Drawable, HasValue
{
   int getX();
   int getY();
}

3. Успадкування класів від інтерфейсів

Клас може успадковуватися від декількох інтерфейсів (але тільки від одного класу). Для цього використовується ключове слово implements. Приклад:

class abstract ChessItem implements Drawable, HasValue
{
   private int x, y, value;
   public int getValue()
   {
      return value;
   }

   public int getX()
   {
      return x;
   }

   public  int getY()
   {
      return y;
   }
}

Клас ChessItem оголошено як абстрактний: він реалізував усі успадковані методи, крім draw. Тобто клас ChessItem містить один абстрактний метод — draw().

Власне, між словами extends та implements різниці немає: обидва слова означають успадкування. Так було зроблено, щоб код був зрозумілішим. Англійською мовою кажуть, що класи успадковуються (extends), а інтерфейси реалізуються (implements).

4. Змінні

І найважливіше: в інтерфейсах не можна оголошувати змінні (проте статичні — можна).

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


18
Задача
Java Syntax Zero,  18 рівень7 лекція
Недоступна
Способи пересування
Створи два інтерфейси — Swimmable і Flyable. У майбутньому їх можна буде використовувати для позначення класів, об'єкти яких уміють плавати або літати.
18
Задача
Java Syntax Zero,  18 рівень7 лекція
Недоступна
Їстівне — неїстівне
Реалізуй інтерфейс Eatable тільки для тих класів із цього списку, об'єкти яких можуть бути їстівними: Apple — яблуко Carrot — морква Fire — вогонь Fish — риба Stone — камінь

2. Відокремлення «опису методів» від їх реалізації.

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

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

Було Стало
class Student
{
   private String name;
   public Student(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;

}
interface Student
{
   public String getName();
}

class StudentImpl implements Student
{
   private String name;
   public StudentImpl(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
}
public static void main(String[] args)
{
   Student student = new Student("Alibaba");
   System.out.println(student.getName());
}
public static void main(String[] args)
{
   Student student = new StudentImpl("Ali")
   System.out.println(student.getName());
}

Ми розділили наш клас на дві частини: інтерфейс і клас, успадкований від інтерфейсу. Які ж переваги ми отримали?

Той самий інтерфейс можуть реалізовувати (успадковувати) різні класи, і кожен із них може мати свою поведінку. Так само, як ArrayList і LinkedList — це дві різні реалізації інтерфейсу List.

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

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


3. Множинне успадкування

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

У Java дійшли компромісу: заборонили множинне успадкування класів, але дозволили множинне успадкування інтерфейсів. Інтерфейс може мати декілька інтерфейсів-батьків. Клас може мати декілька інтерфейсів-батьків, але батьківський клас може бути тільки один.

Чому ж для класів множинне успадкування заборонили, а для інтерфейсів дозволили? Причиною є так зване пірамідальне успадкування:

Множинне успадкування

Коли клас B успадковується від класу A, йому нічого не відомо про класи C і D. Тому він використовує змінні класу A так, як вважає за потрібне. Клас C робить те саме: використовує змінні класу A, але вже в інший спосіб. А в класі D це все призводить до конфлікту.

Розгляньмо простий приклад. Припустімо, у нас є 3 класи:

class Data
{
   protected int value;
}
class XCoordinate extends Data
{
   public void setX (int x) { value = x;}
   public int getX () { return value;}
}
class YCoordinate extends Data
{
   public void setY (int y) { value = y;}
   public int getY () { return value;}
}

Клас Data зберігає змінну value. Його клас-спадкоємець XCoordinate використовує її для зберігання змінної X, а клас-спадкоємець YCoordinate — для зберігання змінної Y.

І це працює — окремо. Але якщо ми захочемо успадкувати клас XYCoordinates від обох класів — XCoordinate і YCoordinate — отримаємо непрацюючий код. У цього класу будуть методи його класів-предків, але працювати вони будуть неправильно, тому що змінна value в них одна.

А оскільки інтерфейсам заборонено мати змінні, то вони не матимуть таких конфліктів. Тому множинне успадкування інтерфейсів дозволено.


18
Задача
Java Syntax Zero,  18 рівень7 лекція
Недоступна
Хай розпочнеться вистава!
Справжній артист повинен уміти розважати людей. Танці та спів — це складові розваги. Перед тобою 3 інтерфейси: Dance — танцюрист, Sing — співак, Artist — артист. Обміркуй, яка структура успадкування підійде цим інтерфейсам. Успадкуй один інтерфейс від двох інших.