Интерфейс
Интерфейс это конструкция языка Java, в рамках которой принято описывать абстрактные публичные ( abstract public ) методы и статические константы ( final static ).
С помощью интерфейса можно указать, что именно должен выполнять класс его реализующий, но не как это делать. Способ реализации выбирает сам класс. Интерфейсы не способны сохранять данные состояния. Интерфейсы — это один из механизмов реализации принципа полиморфизма «один интерфейс, несколько методов».
Рассмотрим следующую картинку. У нас есть контракт (интерфейс), в котором описано какие действия должна выполнять мышка. Это например, клик по правой клавише и клик по левой. Разные производители мышки (классы), реализующие данный контракт (интерфейс), обязаны спроектировать мышки, у которых будут эти действия. Но как выглядят мышки, какие дополнительные опции будут иметь — все это решает сам производитель.
Интерфейсы, как и классы могут быть объявлены с уровнем доступа public или default .
Переменные интерфейса являются public static final по умолчанию и эти модификаторы необязательны при их объявлении. Например, в следующем примере объявлены переменные RIGHT , LEFT , UP , DOWN без каких-либо модификаторов. Но они будут public static final .
Все методы интерфейса являются public abstract и эти модификаторы тоже необязательны. Объявляемые методы не содержат тел, их объявления завершаются точкой с запятой:
public interface Moveable
Чтобы указать, что данный класс реализует интерфейс, в строке объявления класса указываем ключевое слово implements и имя интерфейса. Класс реализующий интерфейс должен содержать полный набор методов, определенных в этом интерфейсе. Но в каждом классе могут быть определены и свои методы. Например, следующий класс Transport реализует интерфейс Moveable . В нем реализованы методы moveRight() и moveLeft() интерфейса Moveable , и добавлены свои методы stop() , start():
public class Transport implements Moveable < public void moveRight() < System.out.println("Транспорт поворачивает вправо."); >public void moveLeft() < System.out.println("Транспорт поворачивает влево."); >public void stop() < System.out.println("Транспорт останавливается."); >public void start() < System.out.println("Транспорт стартует."); >>
Один интерфейс может быть реализован любым количеством классов. Например, в следующей схеме добавлены еще два класса Robot и Device , которые тоже реализуют интерфейс Moveable .

Класс Robot из вышеуказанной схемы:
public class Robot implements Moveable < public void moveRight() < System.out.println("Робот поворачивает вправо."); >public void moveLeft() < System.out.println("Робот поворачивает влево."); >>
Если класс реализует интерфейс, но не полностью реализует определенные в нем методы, он должен быть объявлен как abstract .
Например, класс Device реализует только один метод интерфейса Moveable , поэтому он абстрактный:
public abstract class Device implements Moveable < public void moveRight() < System.out.println("Девайс поворачивает вправо."); >>
Тип интерфейса можно указывать при объявлении переменных, содержащих ссылки на объекты, классы которых реализуют этот интерфейс. Например, в следующем примере переменная moveable имеет тип Moveable , и указывает она на объект Transport . Но на основе интерфейсов нельзя порождать объекты. Например, в строке Moveable moveable1 = new Moveable() будет ошибка компиляции. При использовании переменной типа интерфейс, доступны только те члены класса, которые определены в этом интерфейсе. Например, нельзя вызвать метод start() , используя переменную moveable . А для переменной transport можно:
public class TransportDemo < public static void main(String[] args) < Moveable moveable = new Transport(); Transport transport = new Transport(); Moveable robot = new Robot(); //Moveable moveable1 = new Moveable(); // moveable.start(); moveable.moveRight(); moveable.moveLeft(); System.out.println(); transport.start(); transport.moveRight(); transport.moveLeft(); transport.stop(); System.out.println(); robot.moveLeft(); robot.moveRight(); >>
Один класс может реализовать любое количество интерфейсов. На следующей схеме показан класс Pickup , который реализует два интерфейса CargoAuto и PassengersAuto :

public interface CargoAuto
public interface PassengersAuto
Для указания того, что класс реализует несколько интерфейсов, после ключевого слова implements через запятую перечисляются нужные интерфейсы. Класс Pickup должен определить все методы реализуемых интерфейсов:
public class Pickup implements CargoAuto, PassengersAuto < public void transportCargo() < System.out.println("Везу груз"); >public void transportPassengers() < System.out.println("Везу пассажиров"); >>
2. Внутренние интерфейсы
Интерфейсы объявленные в классах или в других интерфейсах называются внутренние или вложенные. Например, интерфейс NestedIf определен внутри класса A:
public class A < public interface NestedIf < boolean isNotNegative(int x); >>
При обращении к интерфейсу NestedIf требуется указывать имя его внешнего класса — A.NestedIf :
public class B implements A.NestedIf < public boolean isNotNegative(int x) < return x >= 0; > >
public class NestedIfDemo < public static void main(String[] args) < A.NestedIf nif = new B(); if (nif.isNotNegative(10)) < System.out.println("Число 10 не отрицательное."); >if (nif.isNotNegative(-12)) < System.out.println("Этo не будет выведено."); >> >
3. Расширение интерфейсов
Интерфейс может наследоваться от другого интерфейса через ключевое слово extends . Один интерфейс, в отличие от классов, может расширять несколько интерфейсов.
Например, интерфейс Football расширяет интерфейсы TVProgram и Sport . Класс FootballImpl , реализующий интерфейс Football , должен переопределить методы всех трех интерфейсов Football , TVProgram и Sport :

public interface Sport
public interface Hockey extends Sport
public interface TVProgram
public interface Football extends Sport, TVProgram
public class FootballImpl implements Football < @Override public void setHomeTeam(String name) < System.out.println("Setting Home Team"); >@Override public void switchToChannel() < System.out.println("Switching to channel"); >@Override public void homeTeamScored(int points) < System.out.println("Scored"); >@Override public void setVisitingTeam(String name) < System.out.println("Setting visiting team"); >@Override public void visitingTeamScored(int points) < System.out.println("Visiting Team Scored"); >@Override public void endOfQuarter(int quarter) < System.out.println("End of quarter"); >>
4. Интерфейсы маркеры
Интерфейсы маркеры — это интерфейсы, у которых не определены ни методы, ни переменные. Реализация этих интерфейсов придает классу определенные свойства. Например, интерфейсы Cloneable и Serializable , отвечающие за клонирование и сохранение объекта в информационном потоке, являются интерфейсами маркерами. Если класс реализует интерфейс Cloneable , это говорит о том, что объекты этого класса могут быть клонированы.
5. Методы по умолчанию в интерфейсах
В JDK 8 в интерфейсы ввели методы по умолчанию — это методы, у которых есть реализация. Другое их название — методы расширения. Классы, реализующие интерфейсы, не обязаны переопределять такие методы, но могут если это необходимо. Методы по умолчанию определяются с ключевым словом default .
Интерфейс SomeInterface объявляет метод по умолчанию defaultMethod() с базовой реализацией:
public interface SomeInterface < default String defaultMethod() < return "Объект типа String по умолчанию"; >>
Класс SomeInterfaceImpl1 , реализующий этот интерфейс, не переопределяет метод defaultMethod() — так можно.
public class SomeInterfaceImpl1 implements SomeInterface
А если класс SomeInterfaceImpl2 не устраивает реализация по умолчанию, он переопределяет этот метод:
public class SomeInterfaceImpl2 implements SomeInterface < @Override public String defaultMethod() < return "Другая символьная строка"; >>
Создаем два объекта классов SomeInterfaceImpl1 и SomeInterfaceImpl2 , и вызываем для каждого метод defaultMethod() . Для объекта класса SomeInterfaceImpl1 вызовется метод, реализованный в интерфейсе, а для объекта класса SomeInterfaceImpl2 — его собственная реализация:
public class DefaultMethodDemo < public static void main(String[] args) < SomeInterface obj1 = new SomeInterfaceImpl1(); SomeInterface obj2 = new SomeInterfaceImpl2(); System.out.println(obj1.defaultMethod()); System.out.println(obj2.defaultMethod()); >>
Объект типа String по умолчанию Другая символьная строка
6. Статические методы интерфейса
В версии JDK 8, в интерфейсы добавлена еще одна возможность — определять в нем статические методы. Статические методы интерфейса, как и класса, можно вызывать независимо от любого объекта. Для вызова статического метода достаточно указать имя интерфейса и через точку имя самого метода.
public interface MyIf < int getNumber(); static int staticMethod() < return 0; >>
public class StaticMethodDemo < public static void main(String[] args) < MyIf obj1 = new MyIfImp(); System.out.println(obj1.getNumber()); System.out.println(MyIf.staticMethod()); >>
Зачем нужен интерфейс в java?
Зачем нужен интерфейс в java, если в разных классах на прямую могу объявить методы с одинаковыми названиями. Я понимаю, что интерфейс как абстрактный класс или семантическая конструкция.
- Вопрос задан более трёх лет назад
- 19045 просмотров
Комментировать
Решения вопроса 2

Президент Солнечной системы и окрестностей
Для реализации модульности и слабой связанности. Интерфейс — это, по сути, контракт (на «поставляемое» множество и сигнатуры методов).
Принципиальное отличие его от абстрактного класса в том, что в Яве нет множественного наследования и, соответственно, конкретный класс может наследовать только от одного абстрактного. А вот имплементировать разных интерфейсов он может, сколько душе угодно.
Если же учесть при этом, что есть еще и абстрактные методы, становится понятно, что абстрактный класс/методы и интерфейс — инструменты для разных задач.
Классический пример правильного использования интерфейсов — явовские коллекции. Прикиньте, учитывая соображения выше, какой бы это был геморой в использовании, если бы API было сделано не через интерфейсы, а через абстрактные классы 🙂
Ответ написан более трёх лет назад
Нравится 2 2 комментария
EarthFM @EarthFM Автор вопроса
При extends методы можно не переопределять, а при implements методы обязательно нужно переопределить, так зачем их переопределять, если можно на прямую создать методы в нужных классах. Просто, я не совсем понимаю как делают API ) Наверно просто не столкнулся с задачами, которые решают абстрактные классы и интерфейсы)

При extends методы можно не переопределять — только если наследуется от конкретного класса (т.е. если они уже где-то хоть раз были определены)! Если же наследуется от абстрактного класса, то либо и сам наследующий класс должен быть все еще абстрактным, либо таки придется метод имплементировать 🙂 Тут фишка совсем в другом!
Наследование от абстрактных классов позволяет «размазать» имплементацию отдельных методов по разным уровням наследования. На каждом уровне имплементируем то, что к нему относится, а остальные методы оставляем абстрактными, и имплементируем их на других уровнях.
Интерфейс же требует, разумеется, имплементировать все — на то он и контракт. Так что, интерфейс используется именно для закрепления контракта, а абстрактный класс — для структурирования имплементации этого контракта.
вот есть обсуждение В чем суть интерфейсов в программировании?
Я бы сказал что интерфейс это контракт между слоями приложения. У вас есть слои дао, сервисов, может секьюрети и ещё что-то. Между ними есть интерфейсы. А значит вы без труда можете заменить реализацию какого то слоя другой реализацией. Например нечто подобное делает спринг когда создает дополнительную прослойку для управления транзакциями над дао. Так же это бывает удобно при тестировании когда для тестов вы пишете Mock объект
Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
Ответы на вопрос 3
Full-stack developer (Symfony, Angular)
Классический пример — класс логгер. Можно просто не париться и сделать класс Logger со своей реализацией, и везде в клиентском коде (то есть тот код, который этот класс будет использовать) завязать на этот класс.
Но чу, теперь логи у нас должны храниться не в файлах а в базе, внезапно так. У нас меняется конструктор, у нас меняется реализация всех методов (предположим что у нас он один, log(string message, int level, string category);
И хорошо если у нас соблюдается принцип инверсии зависимостей, тогда то что мы конструктор поменяли никак не скажется на клиентсоком коде ибо инстанс просто ему дается а он ничего не знает о том как создавать оный. Но у нас встает делема, либо поиском-заменой менять тип в клиентском коде, либо наследоваться и просто заменять реализацию. В этом плане наследование работать будет так как мы хотим, но зачем?
С интерфейсом у нас есть красивый интерфейс, есть его реализации, если у нас есть контейнер зависимостей то мы можем привязать конкретную реализацию к интерфейсу и там где требуется этот интерфейс будет автоматом засунута нужная реализация. Замена реализации — изменить конфиг DI.
Так же, если вам нужно часто менять интерфейс то у вас уже какие-то проблемы с построением архитектуры. Интерфейс должен быть простым и должен делать что-то одно.
А вообще, почитайте про GRASP и SOLID.
Ответ написан более трёх лет назад
Нравится 1 2 комментария
Инверсия зависимости, конфиг DI, архитектура — вы уверены что человек задавший такой вопрос понимает эти вещи? =D к тому же ваш ответ сильно привязан к IoC и DI, что мягко говоря является оверхедом при ответе на вопрос «для чего нужны интерфейсы».
Зачем нужны интерфейсы?

Зачем нужны интерфейсы? Зачем нужно наследование интерфейсов? Зачем нужен полиморфизм? Для тех, кто почитал и понял как делать интерфейсы, но не понял зачем.
Дисклеймер: В этой статье и последующих, нейминги классов и методов будут приведены на русском языке.
Когда речь заходит о принципах объектно-ориентированного программирования (ООП): полиморфизм, наследование и инкапсуляция, полезно приводить аналогии из реального мира. Большой плюс ООП в том, что мы в программе можем смоделировать часть реальной вселенной. Смоделируем семью Ивановых: Папа, Мама и мальчик Петя. От Папы Петя унаследовал привычку прихлюпывать когда пьет чай, а от Мамы он унаследовал привычку поджимать губы во время чтения. Если попытаться реализовать эту ситуацию в программу, то у нас получиться три класса:
class Папа class Мама class Петя
У Папы и Мамы есть привычки, которые нужно передать Пете. Привычки — это какие-то действия — так что лучше всего реализовать их в программном мире как методы: Сначала Папа:
class Папа < public void прихлюпывать() < System.out.println("Хлюп"); >>
Теперь Мама:
class Мама < public void поджимать() < System.out.println("Поджать губки"); >>
Если речь идет о наследовании, то логично написать код так:
class Петя extends Папа, Мама < @Override public void прихлюпывать() < System.out.println("Хлюп"); >@Override public void поджимать() < System.out.println("Поджать губки"); >>

То есть унаследовать Петю от Папы и Мамы одновременно. Если так написать, то компилятор будет ругаться, потому что в Java нельзя реализовать множественное наследование классов. К слову, в С++ можно, а вот в Java нельзя, потому что с множественным наследованием могут возникнуть большие проблемы: подробно пишут в интернете. Что бы обойти это «нельзя», в Java есть интерфейсы. И для привычек мы придумаем свой интерфейс. Даже два: Выглядеть они будут так:
public interface ПривычкиПапы < public void прихлюпывать(); >public interface ПривычкиМамы
В интерфейсе мы только описали привычки, но не описали что они конкретно делают, потому что конкретную реализацию мы пропишем в классах. Сначала отдадим Папе и Маме их законные привычки.
class Папа implements ПривычкиПапы < @Override public void прихлюпывать() < System.out.println("Хлюп"); >> class Мама implements ПривычкиМамы < @Override public void поджимать() < System.out.println("Поджать губки"); >>
И теперь, абсолютно легально можно передать Пете привычки от Папы и Мамы одновременно
class Петя implements ПривычкиПапы, ПривычкиМамы < @Override public void прихлюпывать() < System.out.println("Хлюп"); >@Override public void поджимать() < System.out.println("Поджать губки"); >>

То есть множественная реализация (чаще говорят имплементация) в Java вполне возможна. Смысл интерфейсов теперь должен быть понятен – в Java с помощью интерфейсов можно реализовать множественное наследование. Если развивать ситуацию дальше, например: ведь у Папы и Мамы наверняка есть привычки, которые они не передали Пете, да и у Пети могут быть свои личные привычки. Как эту жизненную Санта-Барбару перенести в плоскость Java вы узнаете в следующих сериях. Это не единственный пример для понимания интерфейсов.Если не читали следующие статьи, то обязательно прочтите: Интерфейсы в Java (если не открыто, можно выйти из профиля или прочитать в режиме — инкогнито) Для чего в Java нужны интерфейсы — тут реализуйте все примеры из статьи и поизменяйте методы и в интерфейсах и в калассах: наименования методов, сигнатуры (то что метод принимает на вход), типы вывода методов. Разберитесь самостоятельно: — с разницей при имплементации интерфейса с классом и абстрактным классом; — дефолтными методами.
Что такое интерфейсы в Java
Узнайте о ключевых особенностях интерфейсов в Java, их применении для создания гибких и масштабируемых приложений.
Алексей Кодов
Автор статьи
9 июня 2023 в 16:31
Интерфейсы в Java — это ключевой элемент объектно-ориентированного программирования, который предоставляет абстракцию для определения контракта между объектами. В Java, интерфейсы определяются с помощью ключевого слова interface .
Основные особенности интерфейсов
- Интерфейсы могут содержать только объявления методов (абстрактные методы) и константы (статические и финальные переменные).
- Все методы в интерфейсе по умолчанию являются публичными и абстрактными.
- Интерфейсы не могут иметь конструкторов, так как они не могут быть инстанциированы.
- Класс может реализовывать несколько интерфейсов, что позволяет обойти отсутствие множественного наследования в Java.
- Начиная с Java 8, интерфейсы могут содержать статические и дефолтные (с реализацией) методы.
Пример
public interface Animal < // Константа String CATEGORY = "Animal"; // Абстрактный метод void makeSound(); // Статический метод (начиная с Java 8) static void showCategory() < System.out.println("Category: " + CATEGORY); >// Дефолтный метод (начиная с Java 8) default void breathe() < System.out.println("I can breathe"); >> public class Dog implements Animal < @Override public void makeSound() < System.out.println("Woof!"); >> public class Main < public static void main(String[] args) < Dog dog = new Dog(); dog.makeSound(); // Woof! dog.breathe(); // I can breathe Animal.showCategory(); // Category: Animal >>
Java-разработчик: новая работа через 11 месяцев
Получится, даже если у вас нет опыта в IT

Зачем использовать интерфейсы?
- Абстракция: Интерфейсы позволяют определить общий контракт между объектами, скрывая детали реализации.
- Множественное наследование: Java не поддерживает множественное наследование классов, но позволяет классу реализовывать несколько интерфейсов.
- Повышение гибкости: Использование интерфейсов делает код более гибким и масштабируемым, так как можно внести изменения в реализацию без изменения контракта.
Использование интерфейсов в Java-разработке является обязательным навыком для создания гибких и масштабируемых приложений. Удачного изучения!
