1. Що таке інтерфейс?
Якщо абстрактний клас — це креслення будинку, то інтерфейс — радше договір або «контракт» про виконання певних робіт. Наприклад, якщо ви викликаєте сантехніка, ви очікуєте, що він зможе «полагодити кран» та «усунути протікання». Вас не цікавить, як він це зробить; головне — результат. У Java інтерфейс — саме такий контракт: він визначає, які методи мають бути реалізовані, але не каже, як.
Коротко й по суті:
Інтерфейс — це спеціальний тип у Java, який визначає набір методів, які зобовʼязані реалізувати класи, що реалізують цей інтерфейс.
- Інтерфейс описує лише «що робити», але не «як робити».
- До Java 8 інтерфейси не містили реалізації методів.
- Інтерфейс — це чистий контракт: якщо клас реалізує інтерфейс, він має реалізувати всі його методи.
Чому це зручно?
- Клас може реалізовувати кілька інтерфейсів — тобто мати кілька «ролей».
- Дозволяє будувати гнучкі та розширювані архітектури, у яких класи можуть реалізовувати різні можливості.
- Інтерфейси широко використовуються в стандартній бібліотеці Java (наприклад, Comparable, Serializable, Runnable тощо).
2. Синтаксис оголошення інтерфейсу
Оголосити інтерфейс у Java — простіше простого. Для цього використовується ключове слово interface. До Java 8 методи інтерфейсу за замовчуванням вважалися public abstract, навіть якщо цього явно не вказано. Це означає, що метод має бути реалізований у класі, який реалізує інтерфейс.
Приклад інтерфейсу
public interface Movable {
void move(int x, int y);
}
- Тут ми оголосили інтерфейс Movable (можна перекласти як «рухомий» або «той, що вміє рухатися»).
- Усередині оголошено метод move(int x, int y). Немає тіла методу — лише сигнатура. Це і є «контракт»: «якщо ви реалізуєте Movable, реалізуйте move».
Особливості синтаксису
- Методи в інтерфейсі не мають тіла (до Java 8).
- Усі методи інтерфейсу за замовчуванням public abstract (можна не писати явно).
- Інтерфейс може містити лише константи (public static final), а не звичайні поля.
Приклад із константою
public interface Constants {
int MAX_SPEED = 100; // public static final за замовчуванням
}
3. Відмінність інтерфейсу від класу
Інтерфейс — це не клас! Давайте розберемося, у чому різниця.
| Клас (у тому числі абстрактний) | Інтерфейс |
|---|---|
| Може містити поля (стан) | Не може містити поля (лише константи) |
| Може містити реалізацію методів | До Java 8 інтерфейси не могли містити реалізацію, лише сигнатури |
| Можна створити за допомогою new (якщо не абстрактний) | Не можна створити безпосередньо |
| Спадкування лише одне (extends) | Клас може реалізувати кілька інтерфейсів (implements) |
| Використовується для «що це таке» | Використовується для «що вміє робити» |
Клас реалізує інтерфейс за допомогою implements:
public class Robot implements Movable {
@Override
public void move(int x, int y) {
System.out.println("Робот переміщується у точку (" + x + ", " + y + ")");
}
}
- Клас Robot реалізує інтерфейс Movable.
- Ключове слово implements — «реалізує».
- Потрібно реалізувати всі методи інтерфейсу (інакше буде помилка компіляції).
- Не забудьте про анотацію @Override — вона не обов’язкова, але допомагає компілятору й вам не помилитися.
4. Приклад використання інтерфейсу
Давайте напишемо простий приклад, щоб побачити, як це працює в реальному житті. Уявімо, що в нас є інтерфейс Movable, і ми хочемо, щоб різні класи могли «рухатися»: робот, автомобіль, тварина…
Крок 1. Оголошуємо інтерфейс
public interface Movable {
void move(int x, int y);
}
Крок 2. Реалізуємо інтерфейс у класі
public class Robot implements Movable {
@Override
public void move(int x, int y) {
System.out.println("Робот переміщується у точку (" + x + ", " + y + ")");
}
}
Крок 3. Використовуємо інтерфейс
public class Main {
public static void main(String[] args) {
Movable m = new Robot(); // Змінна типу інтерфейсу!
m.move(10, 20); // Виведе: Робот переміщується у точку (10, 20)
}
}
Зверніть увагу:
- Ми можемо оголосити змінну типу інтерфейсу (Movable m) і присвоїти їй обʼєкт класу, який реалізує цей інтерфейс (new Robot()).
- Це дозволяє писати універсальний код, який працює з будь-яким «рухомим» обʼєктом, не знаючи, що це за клас насправді.
Помилка під час компіляції, якщо не реалізувати метод
Error: Class 'Robot' must either be declared abstract or implement abstract method 'move(int, int)' in 'Movable'
Це і є сила інтерфейсу — він гарантує, що всі класи, які його реалізують, матимуть потрібні методи.
5. Інтерфейси у стандартній бібліотеці Java
Інтерфейси — не просто «шкільна» тема. Вони активно використовуються в усій стандартній бібліотеці Java. Ось кілька прикладів:
- Comparable<T> — інтерфейс для порівняння обʼєктів (наприклад, під час сортування).
- Runnable — інтерфейс для запуску потоку.
- Serializable — маркерний інтерфейс, що вказує, що обʼєкт можна серіалізувати.
- List, Set, Map — інтерфейси колекцій.
Приклад: Comparable
public class Person implements Comparable<Person> {
String name;
int age;
// Конструктор та інші методи...
@Override
public int compareTo(Person other) {
return this.age - other.age;
}
}
Тепер обʼєкти Person можна сортувати, оскільки вони реалізують інтерфейс Comparable.
6. Візуальна схема: як працює інтерфейс
+-------------------+ +-------------------+
| interface | | class |
| Movable |<--------| Robot |
|-------------------| |-------------------|
| +move(int, int) | | +move(int, int) |
+-------------------+ +-------------------+
- Стрілка показує, що клас Robot реалізує інтерфейс Movable.
- Інтерфейс визначає лише «що має бути», клас — «як це працює».
Аналогія з життя
Інтерфейс у Java — це як водійські права. Якщо у вас є права (ви реалізуєте інтерфейс «Водій»), отже, ви вмієте керувати автомобілем. Як саме ви це робите — деталі: хтось водить акуратно, хтось — швидко, але головне — ви підписалися під тим, що вмієте це робити.
7. Практичний приклад: продовжуємо наш застосунок
public interface Movable {
void move(int x, int y);
}
public class Animal implements Movable {
protected String name;
public Animal(String name) {
this.name = name;
}
@Override
public void move(int x, int y) {
System.out.println(name + " переміщується у точку (" + x + ", " + y + ")");
}
}
public class Robot implements Movable {
private String model;
public Robot(String model) {
this.model = model;
}
@Override
public void move(int x, int y) {
System.out.println("Робот " + model + " їде до координат (" + x + ", " + y + ")");
}
}
public class Main {
public static void main(String[] args) {
Movable[] movables = {
new Animal("Барсик"),
new Robot("R2D2")
};
for (Movable m : movables) {
m.move(5, 10);
}
}
}
Результат:
Барсик переміщується у точку (5, 10)
Робот R2D2 їде до координат (5, 10)
Ми створили масив обʼєктів типу Movable. У ньому можуть бути будь-які обʼєкти, що реалізують цей інтерфейс! Код у циклі не знає, хто саме перед ним — тварина чи робот, — але знає, що кожен із них уміє move.
8. Типові помилки під час роботи з інтерфейсами
Помилка № 1: спроба створити обʼєкт інтерфейсу безпосередньо. Інтерфейс — це контракт, а не конкретний обʼєкт. Не можна написати new Movable() — це спричинить помилку компіляції. Потрібно створювати обʼєкти класів, що реалізують інтерфейс.
Помилка № 2: не реалізовано всі методи інтерфейсу. Якщо клас реалізує інтерфейс, але не реалізує всі його методи, компілятор видасть помилку: «Class must either be declared abstract or implement abstract method ...». Якщо ви не хочете реалізовувати всі методи — оголосіть клас як abstract.
Помилка № 3: забули про модифікатори доступу. Методи інтерфейсу завжди public (навіть якщо це не написано явно). У класі, що реалізує, не можна знижувати рівень доступу, тому метод також має бути public.
Помилка № 4: спроба додати звичайні поля в інтерфейс. В інтерфейсі можна оголошувати лише константи (public static final). Звичайні (нестатичні) поля додати не можна.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ