Реалізація множинного наслідування через інтерфейси
Так як інтерфейс за визначенням не має реалізації (тобто не володіє пам'яттю для зберігання даних), немає нічого, що могло б перешкодити поєднанню кількох інтерфейсів. Це дуже корисна можливість, так як в деяких ситуаціях потрібно висловити твердження: «Ікс є і А, і Б, і В одночасно».
При спадкуванні базовий клас зовсім не зобов'язаний бути абстрактним або «реальним» (без абстрактних методів). Якщо спадкування дійсно здійснюється не від інтерфейсу, то серед прямих «предків» клас може бути тільки один - всі інші повинні бути інтерфейсами. Імена інтерфейсів перераховуються слідом за ключовим словом implements і розділяються комами. Інтерфейсів може бути скільки завгодно, причому до них можна проводити висхідне перетворення. Наступний приклад показує, як створити новий клас на основі реального класу і декількох інтерфейсів:
// Використання кількох інтерфейсів interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } class ActionCharacter { public void fight() {} } class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly { public void swim() {} public void fly() {} } public class Adventure { public static void t(CanFight x) { x.fight(); } public static void u(CanSwim x) { x.swim(); } public static void v(CanFly x) { x.fly(); } public static void w(ActionCharacter x) { x.fight(); } public static void main(String[] args) { Hero h = new Hero(); t(h); // Використано об'єкт типу CanFight u(h); // Використано об'єкт типу CanSwim v(h); // Використано об'єкт типу CanFly w(h); // Використано об'єкт типу ActionCharacter } }
Клас Неrо поєднує реальний клас Action Character з інтерфейсами CanFight, CanSwim і CanFly. При об'єднанні реального класу з інтерфейсами на першому місці має стояти реальний клас, а за ним слідують інтерфейси (інакше компілятор видасть помилку).
Зауважте, що оголошення методу fight () в інтерфейсі CanFight збігається з тим, що є в класі ActionCharacter, і тому в класі Неrо немає визначення методу fight ().
Інтерфейси можна розширювати, але при цьому виходить інший інтерфейс. Необхідною умовою для створення об'єктів нового типу є наявність всіх визначень. Хоча клас Неrо не має явного визначення методу fight (), це визначення існує в класі ActionCharacter, що і робить можливим створення об'єктів класу Неrо.
Клас Adventure містить чотири методи, які приймають в якості аргументів різноманітні інтерфейси і реальний клас. Створений об'єкт Неrо передається всім цим методам, а це значить, що виконується висхідний перетворення об'єкта до кожного інтерфейсу по черзі.
Система інтерфейсів Java спроектована так, що вона нормально працює без особливих зусиль з боку програміста.
Пам'ятайте, що головна причина введення в мову інтерфейсів представлена в наведеному прикладі: це можливість виконувати висхідне перетворення до декількох базових типів.
Друга причина для використання інтерфейсів збігається з призначенням абстрактних класів: заборонити програмісту-клієнту створення об'єктів цього класу.
Виникає природне запитання: що краще - інтерфейс або абстрактний клас? Якщо можна створити базовий клас без визначень методів і змінних-членів, вибирайте саме інтерфейс, а не абстрактний клас. Взагалі кажучи, якщо відомо, що щось буде використовуватися як базовий клас, насамперед постарайтеся зробити це «щось» інтерфейсом.