JavaRush /Java блог /Random UA /Інтерфейси в Java

Інтерфейси в Java

Стаття з групи Random UA
Вітання! Сьогодні поговоримо про важливе поняття Java — інтерфейси. Слово тобі, напевно, знайоме. Наприклад, інтерфейси є у більшості комп'ютерних програм та ігор. У широкому сенсі інтерфейс — якийсь «пульт», який пов'язує дві сторони, що взаємодіють один з одним. Простий приклад інтерфейсу з повсякденного життя – пульт від телевізора. Він пов'язує два об'єкти, людину та телевізор, і виконує різні завдання: додати або зменшити звук, переключити канали, увімкнути або вимкнути телевізор. Одній стороні (людині) потрібно звернутися до інтерфейсу (натиснути кнопку пульта), щоб друга сторона виконала дію. Наприклад, щоб телевізор переключив канал на наступний. При цьому користувачеві не обов'язково знати пристрій телевізора та те, як усередині нього реалізовано процес зміни каналу.Для чого в Java потрібні інтерфейси?Все, до чого користувач має доступ - це інтерфейс . Головне завдання – отримати потрібний результат. Яке це має відношення до програмування та Java? Пряме :) Створення інтерфейсу дуже схоже створення звичайного класу, тільки замість слова classми вказуємо слово interface. Давай подивимося на найпростіший Java-інтерфейс і розберемося, як він працює і для чого потрібен:
public interface Swimmable  {

     public void swim();
}
Ми створабо інтерфейс Swimmable- " вміє плавати ". Це щось на зразок нашого пульта, який має одну «кнопку»: метод swim() — «плисти». Як же нам цей пульт використовувати? І тому метод, тобто. кнопку нашого пульта потрібно імплементувати. Щоб використати інтерфейс, його методи мають реалізувати якісь класи нашої програми. Давай придумаємо клас, об'єкти якого підійдуть під опис «який вміє плавати». Наприклад, підійде клас качки - Duck:
public class Duck implements Swimmable {

    public void swim() {
        System.out.println("Качечка, пливи!");
    }

    public static void main(String[] args) {

        Duck duck = new Duck();
        duck.swim();
    }
}
Що ми тут бачимо? Клас Duck«зв'язується» з інтерфейсом Swimmableза допомогою ключового слова implements. Якщо пам'ятаєш, ми використовували схожий механізм для зв'язку двох класів у спадкуванні, тільки там було слово extends . « public class Duck implements Swimmable» можна зрозуміло перекласти дослівно: «суспільний клас Duckреалізує інтерфейс Swimmable». Це означає, що клас, пов'язаний з якимось інтерфейсом, має реалізувати всі його методи. Зверніть увагу: в нашому класі Duckпрямо як в інтерфейсі Swimmableє метод swim(), і всередині нього міститься якась логіка. Це обов'язкова вимога. Якби ми просто написали « public class Duck implements Swimmable» і не створабо метод swim()у класі Duck, компілятор видав би нам помилку: Duck is not abstract and does not override abstract method swim() in Swimmable Чому так відбувається? Якщо пояснювати помилку на прикладі з телевізором, то вийде, що ми даємо людині в руки пульт з кнопкою «переключити канал» від телевізора, який не вміє перемикати канали. Тут вже натискай на кнопку, скільки влізе, нічого не заробить. Пульт сам собою не перемикає канали: він лише дає сигнал телевізору, всередині якого реалізовано складний процес зміни каналу. Так і з нашою качкою: вона повинна вміти плавати, щоб до неї можна було звернутися за допомогою інтерфейсу Swimmable. Якщо вона цього не вміє, інтерфейс Swimmableне зв'яже дві сторони – людину та програму. Людина не зможе використовувати метод swim(), щоб змусити об'єктDuckвсередині програми плисти. Тепер ти побачив наочно, для чого потрібні інтерфейси. Інтерфейс визначає поведінка, якою повинні мати класи, що реалізують цей інтерфейс. "Поведінка" - це сукупність методів. Якщо ми хочемо створити кілька месенджерів, найпростіше зробити це, створивши інтерфейс Messenger. Що має вміти будь-який месенджер? У спрощеному вигляді приймати та відправляти повідомлення.
public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
І тепер ми можемо просто створювати наші класи-месенджери, імплементуючи цей інтерфейс. Компілятор сам «змусить» нас реалізувати їх усередині класів. Telegram:
public class Telegram implements Messenger {

    public void sendMessage() {

        System.out.println("Надсилаємо повідомлення в Telegram!");
    }

     public void getMessage() {
         System.out.println("Читаємо повідомлення у Telegram!");
     }
}
WhatsApp:
public class WhatsApp implements Messenger {

    public void sendMessage() {

        System.out.println("Надсилаємо повідомлення в WhatsApp!");
    }

     public void getMessage() {
         System.out.println("Читаємо повідомлення у WhatsApp!");
     }
}
Viber:
public class Viber implements Messenger {

    public void sendMessage() {

        System.out.println("Відправляємо повідомлення у Viber!");
    }

     public void getMessage() {
         System.out.println("Читаємо повідомлення у Viber!");
     }
}
Які переваги це надає? Найголовніше з них – слабка пов'язаність. Уяви, що ми проектуємо програму, в якій у нас буде зібрано дані клієнтів. У класі Clientобов'язково потрібно поле, що вказує, яким саме месенджер клієнт користується. Без інтерфейсів це було б дивно:
public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
Ми створабо три поля, але у клієнта запитто може бути лише один месенджер. Просто ми не знаємо який. І щоб не залишитися без зв'язку з клієнтом, доводиться «заштовхувати» до класу всі можливі варіанти. Виходить, один або два з них завжди будуть nullі вони взагалі не потрібні для роботи програми. Натомість краще використовувати наш інтерфейс:
public class Client {

    private Messenger messenger;
}
Це і є приклад «слабкої пов'язаності»! Замість того, щоб вказувати конкретний клас месенджера в класі Clientми просто згадуємо, що у клієнта є месенджер. Який саме – визначиться у ході роботи програми. Але навіщо для цього саме інтерфейси? Навіщо їх взагалі додали до мови? Питання хороше і правильне! Того ж результату можна досягти за допомогою звичайного успадкування, правда? Клас Messenger- батьківський, а Viber, Telegramі WhatsApp- спадкоємці. Справді, можна й так. Але є одна проблема. Як ти вже знаєш, множинного спадкування в Java немає. А ось численна реалізація інтерфейсів є. Клас може реалізовувати скільки завгодно інтерфейсів. Уяви, що у нас є клас Smartphone, у якого є полеApplication— встановлений на смартфоні програма.
public class Smartphone {

    private Application application;
}
Додаток і месенджер, звичайно, схожі, але це різні речі. Месенджер може бути і мобільним, і десктопним, тоді як Application - це саме мобільний додаток. Так от, якби ми використовували успадкування, не змогли б додати об'єкт Telegramдо класу Smartphone. Адже клас Telegramне може успадковуватися одночасно від Applicationі від Messenger! А ми вже встигли успадкувати його від Messenger, і в такому вигляді додати до класу Client. Але реалізувати обидва інтерфейси клас Telegramзапитто може! Тому в класі Clientми зможемо впровадити об'єкт Telegramяк Messenger, а клас Smartphone— як Application. Ось як це робиться:
public class Telegram implements Application, Messenger {

    //...методи
}

public class Client {

    private Messenger messenger;

    public Client() {
        this.messenger = new Telegram();
    }
}


public class Smartphone {

    private Application application;

    public Smartphone() {
        this.application = new Telegram();
    }
}
Тепер ми використовуємо клас Telegramяк захочемо. Десь він виступатиме в ролі Application, десь — у ролі Messenger. Напевно, ти вже звернув увагу, що методи в інтерфейсах завжди «порожні», тобто вони не мають реалізації. Причина цього проста: інтерфейс описує поведінку, а чи не реалізує його. "Усі об'єкти класів, що імплементують інтерфейс Swimmable, повинні вміти плавати": ось і все, що говорить нам інтерфейс. Як там конкретно плаватиме риба, качка чи кінь — питання до класів Fish, DuckіHorse, а чи не до інтерфейсу. Також як перемикання каналу – завдання телевізора. Пульт просто надає тобі кнопку для цього. Втім, Java8 з'явилося цікаве доповнення - методи за замовчуванням (default method). Наприклад, у твоєму інтерфейсі є десять методів. 9 їх реалізовані по-різному у різних класах, але один реалізований однаково в усіх. Раніше, до виходу Java8, методи всередині інтерфейсів взагалі мали реалізації: компілятор відразу видавав помилку. Тепер можна зробити ось так:
public interface Swimmable {

   public default void swim() {
       System.out.println("Пливи!");
   }

   public void eat();

   public void run();
}
Використовуючи ключове слово defaultми створабо в інтерфейсі метод з реалізацією за умовчанням. Два інших методи, eat()і run()нам необхідно буде реалізувати самим у всіх класах, які будуть імплементувати Swimmable. З swim()цим робити не потрібно: реалізація буде в усіх класах однаковою. До речі, ти вже неодноразово стикався з інтерфейсами в минулих завданнях, хоч і не помічав цього сам :) Ось очевидний приклад: Для чого в Java потрібні інтерфейси?Ти працював з інтерфейсами Listі Set! Точніше, зі своїми реалізаціями — ArrayList, LinkedList, HashSetта іншими. На цій схемі видно приклад, коли один клас реалізує відразу кілька інтерфейсів. Наприклад, LinkedListреалізує інтерфейси Listта Deque(двостороння черга). Ти знайомий і з інтерфейсомMap, А точніше, з його реалізацій - HashMap. До речі, на цій схемі ти можеш побачити одну особливість: інтерфейси можуть бути успадковані один від одного. Інтерфейс SortedMapуспадкований від Map, а Dequeуспадковується від черги Queue. Це потрібно, якщо ти хочеш показати зв'язок інтерфейсів між собою, але один інтерфейс є розширеною версією іншого. Давай розглянемо приклад з інтерфейсом Queue– черга. Ми поки не проходабо колекції Queue, але вони досить прості та влаштовані як звичайна черга у магазині. Додавати елементи можна лише на кінець черги, а забирати — лише з початку. На певному етапі розробникам знадобився розширений варіант черги, щоб додавати та отримувати елементи можна було з обох боків. Так створабо інтерфейсDeque- Двосторонню чергу. У ньому є всі методи звичайної черги, адже вона є «батьком» двосторонньої, але при цьому додані нові методи.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ