Интерфейс — это контракт
Интерфейс объявляет, что класс может делать, не говоря, как. Это список сигнатур методов, которые любой реализующий класс обязуется выполнить. Суть в развязке: код может работать с типом интерфейса и не заботиться о том, какой конкретный класс стоит за ним.
Circle implements Shape означает, что Circle должен определить area и perimeter. Как только он это делает, Circle является Shape и может храниться в переменной типа Shape.
Много классов, один тип
Сила проявляется, когда несколько несвязанных классов реализуют один и тот же интерфейс. Код, написанный под Shape, обрабатывает их все:
Цикл никогда не спрашивает «это Circle или Rectangle?» — он просто вызывает area() и доверяет контракту. Добавление Triangle позже не потребует здесь никаких изменений.
Реализация нескольких интерфейсов
Класс наследует только один класс, но может реализовывать любое число интерфейсов — именно так Java безопасно осуществляет «множественное наследование» поведения:
Перечислите интерфейсы через запятую после implements. Класс должен удовлетворять им всем.
Методы default и static
Начиная с Java 8 интерфейс может содержать тела методов. Метод default даёт реализующим классам готовую реализацию, которую они наследуют бесплатно (и могут переопределить):
Методы default позволяют интерфейсу развиваться — добавлять метод, не ломая каждую существующую реализацию. Метод интерфейса static, напротив, — это утилита, которую вы вызываете у самого интерфейса, как Comparator.naturalOrder().
Константы
Поля в интерфейсе неявно являются public static final — это константы, а не состояние экземпляра:
interface Physics {
double GRAVITY = 9.81; // automatically public static final
}
Интерфейсы традиционно не хранят состояния отдельного объекта; отсутствие полей экземпляра — часть того, что отличает их от классов.
Функциональные интерфейсы
Интерфейс ровно с одним абстрактным методом является функциональным интерфейсом, и его можно реализовать лямбда-выражением вместо целого класса:
Это основа лямбд Java и типов из java.util.function (Function, Predicate, Supplier и им подобных). Аннотация @FunctionalInterface делает намерение явным и позволяет компилятору следить за соблюдением правила единственного метода.
Интерфейс против абстрактного класса
Оба позволяют программировать на уровне абстракции, так когда же выбирать тот или иной?
- Интерфейс — возможность, которую могут разделять несвязанные классы. И
Bird, иAirplaneмогут бытьFlyable. Класс может реализовать множество интерфейсов. Без состояния экземпляра. - Абстрактный класс — общее состояние и код среди тесно связанных классов. И
Cat, иDogнаследуютAnimal, получая общие поля и частично реализованные методы. Класс наследует только один.
Распространённый шаблон сочетает их: интерфейс определяет контракт, а абстрактный класс реализует шаблонные части, чтобы конкретные подклассы заполняли лишь специфические детали.
Далее: абстрактные классы
Интерфейсы определяют поведение без состояния. Абстрактные классы находятся между интерфейсами и полноценными классами — они могут объявлять нереализованные методы и нести поля и конструкторы. Это тема следующей страницы.
Часто задаваемые вопросы
Что такое интерфейс в Java?
Интерфейс — это контракт: набор сигнатур методов (и констант), которые класс обязуется предоставить. Он говорит, что класс может делать, но не как. Класс использует ключевое слово implements, чтобы принять интерфейс, и должен предоставить тело для каждого абстрактного метода, объявленного интерфейсом. Интерфейсы позволяют использовать несвязанные между собой классы взаимозаменяемо через общий тип.
В чём разница между интерфейсом и абстрактным классом в Java?
Класс может реализовывать множество интерфейсов, но наследовать (extends) лишь один (абстрактный) класс. Интерфейсы традиционно не хранят состояния экземпляра и только объявляют поведение, тогда как абстрактный класс может иметь поля, конструкторы и частично реализованную логику. Используйте интерфейс, чтобы определить возможность, которую могут разделять несколько несвязанных классов; используйте абстрактный класс, чтобы делить общее состояние и код между тесно связанными подклассами.
Может ли интерфейс в Java иметь тела методов?
Да, начиная с Java 8. Методы интерфейса, помеченные default, предоставляют тело, которое реализующие классы наследуют (и могут переопределять), а static-методы интерфейса предоставляют служебное поведение, вызываемое у самого интерфейса. Обычные методы интерфейса по-прежнему абстрактны -лишь сигнатура- и реализующие классы должны их определять.