Интерфейс - это публичный общепринятый контракт (соглашение), описывающий некоторое поведение. Для чего они нужны? Например, пусть у нас есть ссылка указывающая на список строк. Предположим этот в этот список в начале добавляется множество элементов, а затем, весь список обрабатывается один раз. Допустим мы решили последовать известной рекомендации и использовать класс ArrayList:
ArrayList<String> list = new ArrayList<>();
Мы написали поведение программы в 100500 строк кода, где использовался этот список строк, и для оптимизации работы использовали методы специфичные для класса ArrayList. Например ensureCapacity(). Пока строки добавляются в конец списка, у нас всё прекрасно и быстро работает. Но вот у нас возникла потребность переориентировать нашу программу на немного другой вид работ, где строки добавляются преимущественно в начало списка. Для такого характера нагрузки гораздо больше подходит LinkedList. Но если мы захотим перевести свою программу из 100500 строк кода на рельсы LinkedList, то нам понадобится отыскать и убрать использование специфичных для ArrayList методов, возможно местами сильно меняя логику отдельных участков программы. Если бы мы использовали только те методы, которые имеются и в ArrayList, и в LinkedList, то нам бы этого делать не пришлось. Мы бы могли всего лишь изменить одну строчку кода - объявление списка:
LinkedList<String> list = new LinkedList<>();
Мы можем заметить, что было бы удобней вынести объявление методов общих, для этих классов, в класс-предок, возможно абстрактный, например AbstractList. В этом случае мы могли бы объявить наш список так:
AbstractList<String> list = new ArrayList<>();
И смогли бы быстро переключить реализацию вот так:
AbstractList<String> list = new LinkedList<>();
Но в этом случае, классы, которые мы можем использовать в нашей программе, ограничены только потомками класса AbstractList, даже если если есть более подходящие под задачу классы, не являющиеся потомками AbstractList, но имеющие те же методы с тем же поведением. Как быть? Именно поэтому были изобретены интерфейсы. Интерфейс - это такое соглашение о наборе методов и их поведении, которое могут обязаться соблюдать совершенно не связанные классы, позволяя ссылаться на любой из них с помощью единой ссылки. Например так:
List<String> list;
list = new ArrayList<>();
list = new LinkedList<>();
list = new AnotherListClass<>();
Даже если AnotherListClass не имеет с классами ArrayList и LinkedList общих классов-предков, кроме Object. Хорошим примером интерфейса, является рулевое управление автомобиля - у автомобиля есть руль, педали и коробка передач. У абсолютного большинства автомобилей, эти элементы следуют одному соглашению о поведении. Например, если повернуть рулевое колесо против часовой стрелки, автомобиль совершит поворот влево, а не увеличит скорость, независимо от своей марки. Если вы умеете использовать эти элементы управления, вы без особых усилий сможете справиться с любым автомобилем, независимо от его модели, года выпуска, марки и типа двигателя. Более того, можно представить ситуацию, в которой совершенно другой вид транспорта (к примеру, космический корабль) имеет тот же интерфейс управления, что и автомобили. Если вы, умея водить автомобиль, попадёте в кресло пилота такого корабля, то сможете не потеряться и в этой ситуации. Ещё раз повторим:
  • Интерфейс это контракт (соглашение) о поведении.
  • Множество классов, даже не связанных отношением наследования, могут объявить, что они обязуются соблюдать этот контракт (имплементация интерфейса).
  • Вынесение описания поведения в отдельный интерфейс очень удобно, так как увеличивает гибкость кода, позволяя переключать реализацию (класс имплементирующий интерфейс) интерфейса, на классы не связанные отношением наследования.