Інтерфейси Java, пояснені прикладами

Інтерфейси

Інтерфейс у Java трохи схожий на Клас, але з істотною різницею: an interfaceможе мати лише підписи методів, поля та методи за замовчуванням. З Java 8 ви також можете створювати методи за замовчуванням. У наступному блоці ви можете побачити приклад інтерфейсу:

public interface Vehicle { public String licensePlate = ""; public float maxVel public void start(); public void stop(); default void blowHorn(){ System.out.println("Blowing horn"); } }

Інтерфейс вище містить два поля, два методи та метод за замовчуванням. Поодинці це не надто корисно, але їх зазвичай використовують разом із класами. Як? Просто, ви повинні переконатись, що хтось класу implementsце.

public class Car implements Vehicle { public void start() { System.out.println("starting engine..."); } public void stop() { System.out.println("stopping engine..."); } }

Тепер існує основне правило : Клас повинен реалізовувати всі методи в Інтерфейсі. Методи повинні мати точно такий самий підпис (ім'я, параметри та винятки), як описано в інтерфейсі. Класу не потрібно оголошувати поля, а лише методи.

Екземпляри інтерфейсу

Після створення класу Java, який є implementsбудь-яким інтерфейсом, на екземпляр об’єкта можна посилатися як на екземпляр інтерфейсу. Ця концепція подібна до концепції створення спадщини.

// following our previous example Vehicle tesla = new Car(); tesla.start(); // starting engine ...

Інтерфейс не може містити методи конструктора. Тому ви не можете створити екземпляр самого інтерфейсу. Ви повинні створити екземпляр якогось класу, що реалізує інтерфейс, щоб посилатися на нього.

Подумайте про інтерфейси як про порожню форму контракту чи шаблон.

Що ви можете зробити з цією функцією? Поліморфізм! Ви можете використовувати лише інтерфейси для посилання на екземпляри об’єктів!

class Truck implements Vehicle { public void start() { System.out.println("starting truck engine..."); } public void stop() { System.out.println("stopping truck engine..."); } } class Starter { // static method, can be called without instantiating the class public static void startEngine(Vehicle vehicle) { vehicle.start(); } } Vehicle tesla = new Car(); Vehicle tata = new Truck(); Starter.startEngine(tesla); // starting engine ... Starter.startEngine(tata); // starting truck engine ...

Але як щодо кількох інтерфейсів?

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

public interface GPS { public void getCoordinates(); } public interface Radio { public void startRadio(); public void stopRadio(); } public class Smartphone implements GPS,Radio { public void getCoordinates() { // return some coordinates } public void startRadio() { // start Radio } public void stopRadio() { // stop Radio } }

Деякі особливості інтерфейсів

  • Ви можете розміщувати змінні в інтерфейсі, хоча це не буде розумним рішенням, оскільки класи не повинні мати однакову змінну. Словом, уникайте розміщення змінних!
  • Усі змінні та методи в Інтерфейсі є загальнодоступними, навіть якщо Ви не використовуєте publicключове слово.
  • Інтерфейс не може вказати реалізацію певного методу. Це залежить від класів. Хоча нещодавно був виняток (див. Нижче).
  • Якщо клас реалізує кілька інтерфейсів, тоді існує віддалений шанс перекриття підпису методу. Оскільки Java не дозволяє використовувати декілька методів одного і того ж підпису, це може призвести до проблем. Докладніше див. У цьому питанні.

Методи інтерфейсу за замовчуванням

До Java 8 ми не мали можливості керувати інтерфейсом для реалізації конкретного методу. Це призводить до великої плутанини та розривів коду, якщо різко змінюється визначення інтерфейсу.

Припустимо, ви написали бібліотеку з відкритим кодом, яка містить інтерфейс. Скажімо, ваші клієнти, тобто практично всі розробники по всьому світу, активно цим користуються і раді. Тепер вам довелося оновити бібліотеку, додавши нове визначення методу до Інтерфейсу для підтримки нової функції. Але це призведе до порушення всіх збірок, оскільки всі класи, що реалізують цей інтерфейс, повинні змінитися зараз. Яка катастрофа!

На щастя, Java 8 тепер пропонує нам defaultметоди інтерфейсів. defaultМетод може містити свою власну реалізацію безпосередньо в інтерфейсі! Отже, якщо клас не реалізує метод за замовчуванням, компілятор прийме реалізацію, зазначену в інтерфейсі. Приємно, чи не так? Тож у вашій бібліотеці ви можете додавати будь-яку кількість методів за замовчуванням в інтерфейси, не боячись щось зламати!

public interface GPS { public void getCoordinates(); default public void getRoughCoordinates() { // implementation to return coordinates from rough sources // such as wifi & mobile System.out.println("Fetching rough coordinates..."); } } public interface Radio { public void startRadio(); public void stopRadio(); } public class Smartphone implements GPS,Radio { public void getCoordinates() { // return some coordinates } public void startRadio() { // start Radio } public void stopRadio() { // stop Radio } // no implementation of getRoughCoordinates() } Smartphone motoG = new Smartphone(); motog.getRoughCoordinates(); // Fetching rough coordinates...

Але що станеться, якщо два інтерфейси мають однаковий підпис методу?

Чудове запитання. У цьому випадку, якщо ви не надасте реалізацію в класі, поганий компілятор заплутається і просто вийде з ладу! Ви також повинні надати реалізацію методу за замовчуванням у класі. Існує також чудовий спосіб superзателефонувати, яка реалізація вам подобається:

public interface Radio { // public void startRadio(); // public void stopRadio(); default public void next() { System.out.println("Next from Radio"); } } public interface MusicPlayer { // public void start(); // public void pause(); // public void stop(); default public void next() { System.out.println("Next from MusicPlayer"); } } public class Smartphone implements Radio, MusicPlayer { public void next() { // Suppose you want to call MusicPlayer next MusicPlayer.super.next(); } } Smartphone motoG = new Smartphone(); motoG.next(); // Next from MusicPlayer

Статичні методи в інтерфейсах

Також новиною для Java 8 є можливість додавання статичних методів до інтерфейсів. Статичні методи в інтерфейсах майже ідентичні статичним методам у конкретних класах. Єдина велика різниця полягає в тому, що staticметоди не успадковуються в класах, що реалізують інтерфейс. Це означає, що на інтерфейс посилається при виклику статичного методу, а не класу, який його реалізує.

interface MusicPlayer { public static void commercial(String sponsor) { System.out.println("Now for a message brought to you by " + sponsor); } public void play(); } class Smartphone implements MusicPlayer { public void play() { System.out.println("Playing from smartphone"); } } class Main { public static void main(String[] args) { Smartphone motoG = new Smartphone(); MusicPlayer.commercial("Motorola"); // Called on interface not on implementing class // motoG.commercial("Motorola"); // This would cause a compilation error } }

Спадкування інтерфейсу

У Java також можливо, щоб інтерфейс успадкував інший інтерфейс, використовуючи, як ви вже здогадалися, extendsключове слово:

public interface Player { public void start(); public void pause(); public void stop(); } public interface MusicPlayer extends Player { default public void next() { System.out.println("Next from MusicPlayer"); } }

Це означає, що MusicPlayerінтерфейс, що реалізує клас , повинен реалізовувати всі методи MusicPlayer, а також Player:

public class SmartPhone implements MusicPlayer { public void start() { System.out.println("start"); } public void stop() { System.out.println("stop"); } public void pause() { System.out.println("pause"); } }

Отже, ви добре розумієте інтерфейси Java! Перейдіть до вивчення абстрактних класів, щоб побачити, як Java дає вам ще один спосіб визначення контрактів.