Интерфейсы в Java
Интерфейсы Java созданы для поддержки динамического выбора (resolution) методов во время выполнения программы. Интерфейсы похожи на классы, но в отличие от последних у интерфейсов нет переменных представителей, а в объявлениях методов отсутствует реализация. Класс может иметь любое количество интерфейсов. Все, что нужно сделать — это реализовать в классе полный набор методов всех интерфейсов. Сигнатуры таких методов класса должны точно совпадать с сигнатурами методов реализуемого в этом классе интерфейса. Интерфейсы обладают своей собственной иерархией, не пересекающейся с классовой иерархией наследования. Это дает возможность реализовать один и тот же интерфейс в различных классах, никак не связанных по линии иерархии классового наследования. Именно в этом и проявляется главная сила интерфейсов.
Интерфейс — это структура данных, которая может содержать поля, представленные в виде именованных констант (ключевое слово final тут обычно не указывается, так как поля — это всегда именованные константы) и объявления методов. Интерфейсом могут расширяться многие классы. Интерфейс может сам расширяться несколькими интерфейсами. Заметим, что интерфейс могут использовать сразу несколько классов, независимых друг от друга.
У интерфейса могут быть следующие модификаторы.
• public (если он есть, то интерфейс доступен отовсюду, если его нет — доступен только в данном пакете).
• abstract (так как интерфейс всегда абстрактный, то модификатор обычно опускается).
• strictfp— все позже реализуемые методы должны будут работать с числами с плавающей точкой аналогично на всех машинах Java.
Приведем пример простого интерфейса, а также класса, который его наследует (листинг 4.13).
Листинг 4.13.
Пример простого интерфейса и класса, который его наследует
interface Apple < String red = "red"; String yellow = "yellow"; String green = "green"; >interface Tangerine < String orange = "orange"; >interface Fruits extends Apple, Tangerine < String fruit1 = "Apple"; String fruit2 = "Tangerine"; void setFruit(int number1, int number2); String getFruit(); >class MyFruits implements Fruits < String color; String name; private String getColor() < return color; >private void setColor(int number) < switch (number) < case 0: this.color = this.red; break; case 1: this.color = this.yellow; break; default: this.color = this.green; >> public String getFruit() < String s = "Fruit: " + this.name + "Color: " + getColor(); return s; >public void setFruit(int number1, int number2) < switch (number1) < case 0: this.name = this.fruit1; setColor(number2); break; default: this.name = this.fruit2; this.color = this.orange; break; >> public static void main(String[] args) < MyFruits my1 = new MyFruits(); my1.setFruit(0, 2); System.out.println(my1.getFruit()); MyFruits my2 = new MyFruits(); my2.setFruit(1, 0); System.out.println(my2.getFruit()); >>
Можно объявить переменную с типом данных, являющимся наименованием интерфейса. Она может ссылаться на объект класса, который реализует интерфейс, и может вызывать методы, которые объявлены в интерфейсе, а реализованы в классе. Чтобы сделать такую ссылку, необходимо в качестве типа данных ссылки указать наименование интерфейса, а после ключевого слова new указать имя конструктора класса (листинг 4.14).
Листинг 4.14.
Объявление переменной с типом данных, являющимся наименованием интерфейса
interface Fruit < void setName(String s); >class Apple implements Fruit < String name; public String getName() < return name; >public void setName(String s) < this.name = s; >public static void main(String[] args) < Fruit my1 = new Apple(); my1.setName("Apple"); System.out.println(my1.getName()); // A это ошибка! Нет метода getName() в интерфейсе Fruit. >>
Локальными переменными называются переменные, объявляемые в каких-либо блоках (повторим еще раз: блоком называется участок кода между двумя фигурными скобками; блоками могут быть: тело метода, блок инициализации и др.). Локальные переменные существуют до тех пор, пока не кончится блок. Как только блок закончится, локальная переменная перестанет существовать.
#19 – Интерфейсы в Джава
Интерфейсы очень схожи с абстрактными классами. Между ними есть всего несколько отличий. За урок мы научимся использовать интерфейсы на практике в Джава, а также узнаем где и зачем их можно использовать.
Видеоурок
Во многих языках программирования реализована возможность множественного наследования, когда один класс имеет несколько классов родителей. В языке Java такой функциональности нет и чтобы решить эту проблему можно использовать интерфейсы.
Что такое интерфейс?
Интерфейсы очень схожи с абстрактными классами и предоставляют лишь методы без реализации.
В интерфейсах можно записать методы, что должны реализовываться во всех классах, использующих интерфейс. Это удобно, ведь за счёт такого функционала мы можем быть уверены в классах и будем знать что они реализовывают все те функции, что мы предусмотрели заранее.
Как создать интерфейс?
Для создания интерфейса используется ключевое слово Interface :
public interface SomeOne
В интерфейсе можно не прописывать модификаторы доступа и по-умолчанию будет проставлен модификатор public.
Для реализации функционала в интерфейсе необходимо создать класс и указать что он является классом, реализующим определенный интерфейс. Для этого после названия класса пропишите слово implements :
class Person implements SomeOne < // Указали реализацию String name; float happiness; int age; Person(String name, float happiness, int age) < this.name = name; this.happiness = happiness; this.age = age; >// Обязательно должны реализовать все методы из интерфейса // Для реализации прописываем слово @Override @Override public void Change (String val) < // Функционал может быть любым, но должен соответсовать описанному методу // К примеру, данная функция ничего не должна возвращать, так как тип данных у неё void this.name = val; System.out.print("Теперь человека зовут - " + val); >>
Для реализации нескольких интерфейсов их можно прописать через запятую в классе после слова implements .
Интерфейсы — Java: Введение в ООП
Классы в Java — основы основ, но их описание будет неполным без интерфейсов, с которыми они тесно связаны. Интерфейсы — более простая конструкция, но, как и в случае с классами, полное понимание интерфейсов требует опыта работы с ними. Зачем они нужны? Интерфейсы позволяют задавать требования к классам, то есть какие методы требуются от класса. Предположим, что мы хотим работать в приложении с генератором паролей. Генератор в нашем случае это обычный класс, с методом generate() , возвращающим пароль.
var generator = new SimplePasswordGenerator(); generator.generate(); // Возвращает готовый пароль generator.generate(); // Уже другой пароль
Теперь с помощью интерфейса опишем требования к классу генератора. Задача интерфейса — определить функционал, который затем будет реализован классами. Поэтому интерфейс содержит только сигнатуру методов без их реализации.
Создадим интерфейс PasswordGenerator и опишем в нем два метода generate() . Один метод будет без параметров, другой — с возможностью настройки длины пароля:
interface PasswordGenerator String generate(); String generate(int length); >
Теперь интерфейс нужно реализовать. Делается это в определении класса:
// Ключевое слово implements означает, что класс реализует интерфейс PasswordGenerator class SimplePasswordGenerator implements PasswordGenerator public String generate() // Обращаемся к методу объекта // 16 – выбранное значение по умолчанию return this.generate(16); > public String generate(int length) // Тут логика генерации простого пароля > >
Интерфейсы не ограничивают класс в его расширении. Помимо интерфейсных методов, мы можем добавить и любые другие.
Но все таки одно ограничение есть. Если класс применяет интерфейс, то он должен реализовывать все методы, указанные в интерфейсе, причем именно так, как они описаны.
Хорошо, вот мы ввели интерфейс, что он нам дал? Если коротко: полиморфизм, а если точнее — полиморфизм подтипов (subtyping). Прямо сейчас он нам не очень нужен, но для общего развития попробуем ухватить его идею. Осторожно, дальнейший текст может напугать. Если он кажется вам сложным, просто пропустите, все это мы будем повторять еще не раз.
Код, который будет использовать passwordGenerator может выглядеть так:
class UserController // Здесь создаются пользователи // Этот код вызывается где-то внутри приложения при регистрации пользователя public void create() // Создаем пользователя // И где-то тут же генерируем ему пароль var generator = new SimplePasswordGenerator(); var password = generator.generate(); > >
Неплохой код, но представьте, что класс может меняться без изменения кода, просто в зависимости от того, какие опции выбирает пользователь при генерации пароля. Вполне реальная ситуация. Самый простой способ реализовать такую схему — вставить условие на параметр, который вводит пользователь. В одном случае берем один класс, в другом другой.
var generator; if (userChooseSomething) generator = new SimplePasswordGenerator(); > else generator = new SuperPasswordGenerator(); >
Такой код уже может стать проблемой, если генераторы будут постоянно добавляться. Ситуация ухудшится, когда эта конструкция начнет расползаться по разным частям проекта. Интерфейсы изящно решают такие ситуации.
Сделаем так, чтобы класс SuperPasswordGenerator() тоже реализовывал интерфейс PasswordGenerator :
class SuperPasswordGenerator implements PasswordGenerator public String generate() return this.generate(16); > public String generate(int length) // Тут уже другая логика генерации супер-сложного пароля > >
Код, который будет использовать PasswordGenerator , меняется на такой:
class UserController // Интерфейс = Тип // Вместо конкретного класса указываем интерфейс public void create(PasswordGenerator generator) var password = generator.generate(); > >
Интерфейсы в Java — это настоящие типы данных, поэтому их можно указывать в определениях методов.
В коде выше видно, что мы требуем передавать в метод create тип PasswordGenerator . Таким типом будет любой объект, класс которого реализует интерфейс PasswordGenerator . Теперь мы можем передать в метод create() любой генератор паролей, который реализует интерфейс PasswordGenerator . В получившемся коде генератор создается не там, где используется. Он создается где-то раньше, а уже в код приходит нужная реализация.
Таким образом мы можем получить разное поведение, не меняя сам код, который использует PasswordGenerator .
Все это уже станет актуальным, как только мы дойдем до Java-коллекций.
Соглашения и правила
К интерфейсам предъявляются такие же требования как и к классам
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Что такое интерфейсы в 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-разработке является обязательным навыком для создания гибких и масштабируемых приложений. Удачного изучения!