1. Способности
Чтобы лучше понять преимущества интерфейсов и места их использования, нужно поговорить о более абстрактных вещах.
Класс — это, чаще всего модель какого-то конкретного объекта. Интерфейс же больше соответствует не объектам, а их способностям или ролям.

Например, такие вещи, как машина, велосипед, мотоцикл и колесо лучше всего представить в виде классов и объектов. А такие их способности, как «могу ездить», «могу перевозить людей», «могу стоять», лучше представить в виде интерфейсов. Вот несколько примеров:
Код | Описание |
---|---|
|
соответствует способности передвигаться |
|
соответствует способности управляться водителем |
|
соответствует способности перевозить грузы |
|
класс Wheel (колесо) обладает способностью передвигаться |
|
класс Car (машина) обладает способностью передвигаться, управляться человеком и перевозить грузы |
|
класс Skateboard (скейтборд) обладает способностью передвигаться и управляться человеком |
2. Роли
Интерфейсы сильно упрощают жизнь программиста. Очень часто в программе есть тысячи объектов, сотни классов и всего пара десятков интерфейсов — ролей. Ролей мало, а их комбинаций — классов — очень много.
Весь смысл в том, что вам не нужно писать код для взаимодействия всех классов со всеми. Вам достаточно взаимодействовать с их ролями (интерфейсами).
Представьте, что вы дрессируете домашних животных, каждое из которых может иметь несколько разных способностей. И вы поспорили с соседом, чьи животные громче кричат. Вы просто берете всех, у которых есть способность «голос», и командуйте им: Голос!.
Вам все равно, что это за животные и какие у них есть другие способности. Хоть тройное сальто назад. В этот конкретный момент вас интересует только способность громко орать. Вот как это выглядело бы в коде:
Код | Описание |
---|---|
|
Способность Звучание . Понимает команду голос — имеет соответствующий метод. |
|
Животные, у которых есть эта особенность.
Для удобства мы дали классам имена на русском. Такое допускается в Java, но крайне нежелательно.
|
|
И как дать им команду? |
Когда количество классов в ваших программах пойдет на тысячи, вы жить без интерфейсов не сможете. Вместо описания взаимодействия тысяч классов, достаточно описать взаимодействие десятков интерфейсов — это очень сильно упрощает жизнь.
А в совокупности с полиморфизмом — это вообще бомба.
3. default
реализация в методах интерфейсов
Абстрактные классы могут иметь переменные и реализацию методов, но для них множественное наследование запрещено. Интерфейсы не могут иметь переменные и реализации методов, и для них множественное наследование разрешено.
Можно эту ситуацию выразить в таблице:
Способность | Абстрактные классы | Интерфейсы |
---|---|---|
Переменные | ✔ | ✖ |
Реализация методов | ✔ | ✖ |
Множественное наследование | ✖ | ✔ |
И вот некоторым программистам очень хотелось, чтобы у интерфейсов была возможность иметь реализацию методов. Иметь возможность добавить реализацию метода — это же не значит, что ее всегда обязательно будут добавлять. Хочешь добавляй, хочешь — нет.
К тому же, проблемы с множественным наследованием в первую очередь из-за переменных. В общем, решили и сделали. Начиная с JDK 8, в Java появилась возможность добавлять в интерфейсы методы с реализацией.
Новая актуальная таблица (для JDK 8 и выше):
Способность | Абстрактные классы | Интерфейсы |
---|---|---|
Переменные | ✔ | ✖ |
Реализация методов | ✔ | ✔ |
Множественное наследование | ✖ | ✔ |
Теперь и в абстрактных классах, и в интерфейсах можно объявлять как методы с реализацией, так и без нее. И это отличная новость!
В абстрактных классах перед методами без реализации нужно писать ключевое слово abstract
, а перед методами с реализацией ничего добавлять не нужно. В интерфейсах же все наоборот. Если у метода нет реализации, ничего добавлять не нужно, если же реализация есть, нужно добавить ключевое слово default
.
Для простоты приведем эту информацию в виде небольшой таблички:
Способность | Абстрактные классы | Интерфейсы |
---|---|---|
Методы без реализации | abstract |
– |
Методы с реализацией | – | default |
Проблема
С помощью интерфейсов с методами можно значительно упростить иерархии многих классов. Например, абстрактные классы InputStream
и OutputStream
можно объявить интерфейсами! Это позволит использовать их гораздо чаще и гораздо удобнее.
Но в мире уже написаны десятки миллионов (миллиарды?) Java-классов. И если начать менять стандартные библиотеки, то есть риск, что что-то может поломаться. Например, всё! 😛
Чтобы случайно не сломать работающие программы и библиотеки, было решено, что реализация методов в интерфейсах получит самый низкий приоритет при наследовании.
Например, если от интерфейса с методом унаследовать второй интерфейс и в нем объявить этот же метод, но без реализации, то реализация из первого метода до класса не дойдет. Пример:
interface Pet
{
default void meow()
{
System.out.println("Мяу");
}
}
interface Cat extends Pet
{
void meow(); // тут мы перекрыли дефолтную реализацию ее отсутствием
}
class Barsik implements Cat
{
}
Код не скомпилируется, т.к. в классе Barsik
не реализован метод meow()
.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ