1. Способности
За да разберем по-добре предимствата на интерфейсите и къде да ги използваме, трябва да говорим за някои по-абстрактни неща.
Един клас обикновено моделира определен обект. Интерфейсът съответства по-малко на обектите и повече на техните способности or роли.
Например, неща като автомобor, велосипеди, мотоциклети и колела са най-добре представени като класове и обекти. Но техните способности - като "Мога да бъда язден", "Мога да транспортирам хора", "Мога да стоя" - са по-добре представени като интерфейси. Ето няколко примера:
Код | Описание |
---|---|
|
Съответства на способността за движение |
|
Съответства на способността да бъде язден |
|
Съответства на способността за транспортиране на неща |
|
Класът Wheel може да се движи |
|
Класът Car може да се движи, да бъде язден и да транспортира неща |
|
Класът Skateboard може да се движи и да бъде язден |
2. Роли
Интерфейсите значително опростяват живота на програмиста. Много често една програма има хиляди обекти, стотици класове, но само няколко дузини интерфейси , т.е. роли . Има малко роли, но има много начини да ги комбинирате (класове).
Целият смисъл е, че не е нужно да пишете code във всеки клас, за да взаимодействате с всеки друг клас. Просто трябва да взаимодействате с техните роли (интерфейси).
Представете си, че сте дресьор на домашни любимци. Всеки от домашните любимци, с които работите, може да има няколко различни способности. Влизате в приятелски спор със съседа си относно това чии домашни любимци могат да вдигат най-много шум. За да разрешите въпроса, просто подреждате всички домашни любимци, които могат да "говорят", и им давате команда: Говорете!
Не ви интересува Howъв вид животно са or Howви други способности имат. Дори да могат да направят тройно салто назад. В този конкретен момент ви интересува само способността им да говорят високо. Ето How ще изглежда в codeа:
Код | Описание |
---|---|
|
Способността CanSpeak . Този интерфейс разбира командата за speak , което означава, че има съответен метод. |
|
Животни, които имат тази функция.
За да улесним разбирането, предоставихме имената на класовете на английски. Това е разрешено в Java, но е крайно нежелателно.
|
|
И How да им дадем команда? |
Когато броят на класовете във вашите програми достигне хиляди, вие няма да можете да живеете без интерфейси. Вместо да се описва взаимодействието на хиляди класове, достатъчно е да се опише взаимодействието на няколко десетки интерфейса - това значително опростява живота.
И когато се комбинира с полиморфизъм, този подход като цяло е смазващ успех.
3. default
Реализация на интерфейсни методи
Абстрактните класове могат да имат променливи и реализации на методи, но не могат да имат множествено наследяване. Интерфейсите не могат да имат променливи or реализации на методи, но могат да имат множествено наследяване.
Ситуацията е представена в следната table:
Способност/свойство | Абстрактни класове | Интерфейси |
---|---|---|
Променливи | ✔ | ✖ |
Изпълнение на метода | ✔ | ✖ |
Множествено наследяване | ✖ | ✔ |
И така, някои програмисти наистина искаха интерфейсите да имат способността да имат имплементации на методи. Но наличието на възможност за добавяне на реализация на метод не означава, че такава винаги ще бъде добавена. Добавете го, ако искате. Или ако не го правите, тогава недейте.
В допълнение, проблемите с множественото наследяване се дължат предимно на променливи. Във всеки случай те така решиха и направиха. Започвайки с JDK 8, Java въведе възможността за добавяне на реализации на методи към интерфейсите.
Ето актуализирана table (за JDK 8 и по-нова):
Способност/свойство | Абстрактни класове | Интерфейси |
---|---|---|
Променливи | ✔ | ✖ |
Изпълнение на метода | ✔ | ✔ |
Множествено наследяване | ✖ | ✔ |
Сега за абстрактни класове, Howто и за интерфейси, можете да декларирате методи със or без реализация. И това е отлична новина!
В абстрактните класове методите без имплементация трябва да бъдат предшествани от abstract
ключовата дума. Не е необходимо да добавяте нищо преди методи с имплементация. При интерфейсите е точно обратното. Ако методът няма имплементация, тогава нищо не трябва да се добавя. Но ако има имплементация, тогава default
трябва да се добави ключовата дума.
За простота представяме тази информация в следната малка table:
Способност/свойство | Абстрактни класове | Интерфейси |
---|---|---|
Методи без реализация | abstract |
– |
Методи с реализация | – | default |
проблем
Използването на интерфейси, които имат методи, може значително да опрости големи йерархии на класове. Например, абстрактното InputStream
и OutputStream
класовете могат да бъдат декларирани като интерфейси! Това ни позволява да ги използваме много по-често и много по-удобно.
Но вече има десетки мorони (мorарди?) Java класове в света. И ако започнете да променяте стандартните библиотеки, тогава може да счупите нещо. Като всичко! 😛
За да не се разрушат случайно съществуващи програми и библиотеки, беше решено внедряването на метод в интерфейсите да има най-нисък приоритет на наследяване .
Например, ако един интерфейс наследява друг интерфейс, който има метод, и първият интерфейс декларира същия метод, но без имплементация, тогава имплементацията на метода от наследения интерфейс няма да достигне до наследяващия интерфейс. Пример:
interface Pet
{
default void meow()
{
System.out.println("Meow");
}
}
interface Cat extends Pet
{
void meow(); // Here we override the default implementation by omitting an implementation
}
class Tom implements Cat
{
}
Кодът няма да се компorра, защото Tom
класът не имплементира meow()
метода.
GO TO FULL VERSION