Как сделать интерфейс в java
Интерфейс Java немного похож на класс, за исключением того, что интерфейс может содержать только сигнатуры методов и поля. Интерфейс не может содержать реализацию методов, только подпись(имя, параметры и исключения) метода.
Вы можете использовать их как способ достижения полиморфизма.
Пример интерфейса Java
Вот простой пример интерфейса Java:
Как видите, интерфейс объявляется с использованием ключевого слова. Как и в случае с классами, интерфейс может быть объявлен как общедоступный или пакетный(без модификатора доступа).
Приведенный выше пример содержит одну переменную и один метод. Доступ к переменной можно получить непосредственно из интерфейса, например так:
Как видите, доступ к переменной очень похож на доступ к статической переменной в классе.
Однако этот метод должен быть реализован некоторым классом, прежде чем вы сможете получить к нему доступ. Следующий раздел объяснит, как это сделать.
Реализация интерфейса
Вот класс, который реализует интерфейс MyInterface, показанный выше:
Обратите внимание, реализует часть MyInterface вышеупомянутого объявления класса. Это сообщает компилятору Java, что класс MyInterfaceImpl реализует интерфейс MyInterface.
Класс, реализующий интерфейс, должен реализовывать все методы, объявленные в нем. Методы должны иметь точно такую же сигнатуру(имя + параметры), как объявлено. Класс не должен реализовывать(объявлять) переменные интерфейса. Только методы.
Экземпляры интерфейса
Как только класс Java реализует интерфейс Java, вы можете использовать экземпляр этого класса в качестве экземпляра. Вот пример:
Обратите внимание, как объявлена переменная типа интерфейса MyInterface, в то время как созданный объект имеет тип MyInterfaceImpl. Java позволяет это, потому что класс MyInterfaceImpl реализует MyInterface. Затем вы можете ссылаться на экземпляры класса MyInterfaceImpl как на экземпляры MyInterface.
Вы не можете создавать экземпляры интерфейса самостоятельно. Вы должны всегда создавать экземпляр некоторого класса, который реализует интерфейс, и ссылаться на этот экземпляр как на экземпляр интерфейса.
Реализация нескольких интерфейсов
Класс Java может реализовывать несколько интерфейсов. В этом случае класс должен реализовать все методы, объявленные во всех реализованных интерфейсах. Вот пример:
Этот класс реализует два, называемых MyInterface и MyOtherInterface. Вы перечисляете имена для реализации после ключевого слова Implements, разделенных запятой.
Если интерфейсы не находятся в тех же пакетах, что и реализующий класс, вам также необходимо импортировать их. Они импортируются с помощью инструкции импорта. Например:
реализованные классом выше:
Как видите, каждый интерфейс содержит один метод. Эти методы реализуются классом MyInterfaceImpl.
Перекрывающиеся подписи метода
Если класс реализует несколько интерфейсов, существует риск, что некоторые могут содержать методы с одинаковой сигнатурой(имя + параметры). Поскольку класс может реализовывать метод только с заданной сигнатурой только один раз, это может привести к проблемам.
Спецификация не дает никакого решения этой проблемы. Вам решать, что делать в этой ситуации.
Какие типы Java могут реализовывать интерфейсы?
Следующие типы могут реализовывать интерфейсы:
- Класс;
- абстрактный класс; ; ;
- Динамический Прокси
Переменные интерфейса
Интерфейс может содержать как переменные, так и константы. Однако часто не имеет смысла помещать переменные. В некоторых случаях может иметь смысл определять константы.
Особенно, если эти константы должны использоваться классами, например, в вычислениях, или в качестве параметров для некоторых методов. Я советую вам избегать размещения переменных.
Все переменные в интерфейсе являются открытыми, даже если вы опустите ключевое слово public в объявлении переменной.
Методы интерфейса
Интерфейс может содержать одно или несколько объявлений метода. Как упоминалось ранее, он не может указывать какую-либо реализацию для этих методов. Это зависит от классов, чтобы определить реализацию.
Все методы являются открытыми, даже если вы опустите ключевое слово public в объявлении метода.
Методы интерфейса по умолчанию
До Java 8 интерфейсы не могли содержать реализацию методов, а содержали только сигнатуры методов. Однако это приводит к некоторым проблемам, когда API необходимо добавить метод.
Если API просто добавляет метод, все классы, которые реализуют интерфейс, должны реализовать этот новый метод. Это хорошо, если все реализующие классы расположены в API. Но если некоторые реализующие классы находятся в клиентском коде API(код, который использует API), то этот код нарушается.
Посмотрите на этот интерфейс и представьте, что он является частью, например, API с открытым исходным кодом, который многие приложения используют внутри:
Теперь представьте, что проект использует этот API и реализовал ResourceLoader следующим образом:
Если разработчик API хочет добавить еще один метод в ResourceLoader, то класс FileLoader будет нарушен при обновлении этого проекта до новой версии API.
Чтобы облегчить эту проблему, Java 8 добавила концепцию. Метод интерфейса по умолчанию может содержать реализацию этого метода по умолчанию. Классы, которые реализуют интерфейс, но не содержат реализации по умолчанию, автоматически получат реализацию метода по умолчанию.
Вы помечаете метод как метод по умолчанию, используя ключевое слово. Вот пример:
В этом примере добавляется метод загрузки по умолчанию(Path). В примере не учитывается фактическая реализация(внутри тела метода), потому что это не очень интересно. Важно то, как вы объявляете метод по умолчанию.
Класс может переопределить реализацию метода по умолчанию просто путем явной реализации этого метода, как это обычно делается.
Статические методы интерфейса
Статические методы в Java должны иметь реализацию.
Вызов статического метода выглядит и работает так же, как вызов статического метода в классе. Вот пример вызова статического метода print() из вышеуказанного MyInterface:
Статические методы в интерфейсах могут быть полезны, когда у вас есть несколько служебных методов, которые вы хотели бы сделать доступными. Например, Vehicle может иметь статический метод printVehicle(Vehicle v).
Интерфейсы и наследование
Интерфейс Java может наследоваться от другого, как классы могут наследовать от других классов. Вы указываете наследование, используя ключевое слово extends.
MySubInterface расширяет MySuperInterface. Это означает, что MySubInterface наследует все поля и методы от MySuperInterface. Это означает, что если класс реализует MySubInterface, этот класс должен реализовать все методы, определенные как в MySubInterface, так и в MySuperInterface.
Можно определить методы в подинтерфейсе с той же сигнатурой(имя + параметры), что и методы, определенные в суперинтерфейсе, если вы считаете, что это будет лучше в вашем проекте.
В отличие от классов, интерфейсы могут наследоваться от нескольких суперинтерфейсов. Вы указываете это, перечисляя имена всех интерфейсов для наследования, разделенных запятой. Класс, реализующий интерфейс, который наследуется от нескольких, должен реализовывать все методы интерфейса и его суперинтерфейсов.
Вот пример интерфейса Java, который наследуется от нескольких интерфейсов:
Как и при реализации нескольких интерфейсов, не существует правил для того, как вы обрабатываете ситуацию, когда несколько суперинтерфейсов имеют методы с одинаковой сигнатурой(имя + параметры).
Наследование и методы по умолчанию
Методы интерфейса по умолчанию немного усложняют правила наследования интерфейса. Хотя обычно класс может реализовать несколько интерфейсов, даже если интерфейсы содержат методы с одинаковой сигнатурой, это невозможно, если один или несколько из этих методов являются методами по умолчанию. Другими словами, если два интерфейса содержат одну и ту же сигнатуру метода(имя + параметры) и один из интерфейсов объявляет этот метод как метод по умолчанию, класс не может автоматически реализовать оба интерфейса.
Ситуация такая же, если интерфейс расширяет(наследует) несколько интерфейсов, и один или несколько из этих интерфейсов содержат методы с одинаковой сигнатурой, а один из суперинтерфейсов объявляет перекрывающийся метод как метод по умолчанию.
В обеих вышеупомянутых ситуациях компилятор Java требует, чтобы класс, реализующий интерфейс(ы), явно реализовал метод, который вызывает проблему. Таким образом, нет сомнений в том, какую реализацию будет иметь класс. Реализация в классе имеет приоритет над любыми реализациями по умолчанию.
Интерфейсы и полиморфизм
Java-интерфейсы – это способ достижения полиморфизма. Полиморфизм – это концепция, которая требует некоторой практики и мысли, чтобы овладеть ею. По сути, полиморфизм означает, что экземпляр класса(объекта) можно использовать так, как если бы он был разных типов. Здесь тип означает либо класс, либо интерфейс.
Посмотрите на эту простую диаграмму классов:
Приведенные выше классы являются частями модели, представляющей различные типы транспортных средств и водителей, с полями и методами. Это ответственность этих классов – моделировать эти сущности из реальной жизни.
Теперь представьте, что вам нужно иметь возможность хранить эти объекты в базе данных, а также сериализовать их в XML, JSON или другие форматы. Вы хотите, чтобы это было реализовано с использованием одного метода для каждой операции, доступного для каждого объекта Car, Truck или Vehicle. Метод store(), метод serializeToXML() и метод serializeToJSON().
Пожалуйста, забудьте на некоторое время, что реализация этой функциональности как методов непосредственно на объектах может привести к грязной иерархии классов. Просто представьте, что именно так вы хотите выполнить операции.
Где в приведенной выше схеме вы бы поместили эти три метода, чтобы они были доступны для всех классов?
Одним из способов решения этой проблемы было бы создание общего суперкласса для класса Vehicle и Driver, который имеет методы хранения и сериализации. Однако это приведет к концептуальному беспорядку. Иерархия классов больше не будет моделировать транспортные средства и водителей, но также будет привязана к механизмам хранения и сериализации, используемым в вашем приложении.
Лучшим решением было бы создать некоторые интерфейсы с включенными методами хранения и сериализации и позволить классам реализовать эти интерфейсы. Вот примеры таких интерфейсов:
Когда каждый класс реализует эти два интерфейса и их методы, вы можете получить доступ к методам этих интерфейсов, приведя объекты к экземплярам типов интерфейса. Вам не нужно точно знать, к какому классу относится данный объект, если вы знаете, какой интерфейс он реализует.
Как вы уже, наверное, можете себе представить, интерфейсы предоставляют более понятный способ реализации сквозных функций в классах, чем наследование.
Универсальные интерфейсы
Этот интерфейс представляет интерфейс, который содержит единственный метод, который называется производством(), который может произвести единственный объект. Так как возвращаемое значение yield() – Object, он может возвращать любой объект Java.
Как вы можете видеть, поскольку универсальный тип для экземпляра CarProducer установлен на Car, больше нет необходимости приводить объект, возвращенный из метода yield(), поскольку в объявлении исходного метода в интерфейсе MyProducer указано, что этот метод возвращает тот же тип, который указан в универсальном типе при использовании.
Как вы можете видеть, по-прежнему нет необходимости приводить объект, возвращаемый функциейручки(), поскольку реализация CarProducer объявляет, что это экземпляр Car.
Обобщения Java более подробно описаны в моем руководстве по обобщению Java.
Функциональные интерфейсы
С Java 8 была введена новая концепция, называемая функциональными интерфейсами. Короче говоря, функциональный интерфейс – это интерфейс с единственным нереализованным методом(нестандартный, нестатический метод). Я объяснил функциональные интерфейсы в моем учебнике по функциональному интерфейсу Java, который является частью моего учебника по функциональному программированию на Java. ,
В статье рассматривается одно из свойств Java, как языка объектно-ориентированного программирования, вопрос использования интерфейса. Статья в большей степени ориентирована на философию Java, чем на практические рекомендации по программированию.
Первый вопрос, возникающий при знакомстве с Java, - Зачем нужны интерфейсы? Нельзя ли обойтись абстрактными классами? Может быть для маскировки отсутствия множественного наследования?
Привычные варианты ответа: класс вводит новый тип, класс обобщает и т.д.
Декларация типа
В Java новый тип можно определить спецификацией интерфейса. Любой java интерфейс (interface) может иметь много реализаций. Любой класс может реализовывать несколько интерфейсов.
В качестве примера создадим интерфейс INumber - тип, описывающий функции использования числовых значений. Ограничимся только операциями сложения и умножения.
Реализация интерфейса, implements
Пример реализации интерфейса INumber при описании класса целочисленных значений :
В классе IntNumber реализованы (переопределены) методы интерфейса с использованием аннотации Override.
Пример использования интерфейса INumber :
В результате выполнения примера "TestINumber" в консоль будет выведен следующий текст :
Из приведенного примера видно :
- Интерфейс позволяет объявить тип. В приведенном примере объявляются переменные и параметры типа INumber, описываются действия над ними. Компиляция выполняется без ошибок.
- Реализация типа передается через объект. Объекты n1, n2 и n3 передаются в метод calculation через параметры. Таким образом компилятор информируется, что объекты проинициализированы где-то за пределами данного модуля. Этого достаточно и классы пока не нужны.
Добавим вариант реализации интерфейса при создании класса вещественного числа :
Протестируем классы, реализующие интерфейс INumber :
Результат выполнения тестовой программы:
Следует обратить внимание, что реализация передается через объект. Класс нужен для порождения объекта, несущего реализацию. Но не обязательно, как увидим позднее. Интересно отметить, что результат операции над INumber зависит от последовательности использования переменных. Эффект возникает потому, что в спецификации типа мы опустили важные для чисел свойства: точность и диапазон допустимых значений. В результате они неявно берутся из базового типа, использованного при реализации.
Реализация интерфейса
В предыдущем примере мы видели, что реализация передается через объект. Следовательно, в объекте упакована вся необходимая информация по реализации интерфейса. Если поведение определяется интерфейсом, а реализация упакована в объекте, то зачем нужен класс? - Классы нужны для наследования реализации и повторного использования кода. Если повторное использование объекта не требуется, то и описание в виде класса не нужно.
В следующем примере класс используется только для запуска приложения. Логика программы реализована на трех интерфейсах без использования классов!
Использование класса Sheep позволило бы сократить текст программы. Никаких других преимуществ введение этого класса не дает. Для остальных объектов определение соответствующих классов не дает ничего. Результат выполнения программы :
Анонимный класс
Можно сказать, что в приведенном выше примере использованы анонимные классы, и мы будем правы.
Но что такое анонимный класс? В спецификации Java сказано: декларация анонимного класса автоматически извлекается компилятором из выражения создания экземпляра класса. Анонимный класс является подклассом существующего класса или реализации интерфейса, и анонимный класс не имеет имени.
Обычно, для того, чтобы создать объект, необходимо сначала декларировать класс. С анонимным классом все наоборот - сначала описывается экземпляр, а потом под него подгоняется класс. Можно сказать, что анонимный класс нужен для того, чтобы узаконить существование созданного объекта. То есть, в данном случае класс - это техническое средство для упаковки реализации; небольшой, относительно автономный кусочек программы (данные + код).
Но если этот кусочек необходимо повторить, то тогда имеет смысл сделать его доступным из разных частей программы. Таким образом, класс нужен только для повторного использования. Кроме того, в большой программе выделение кода в классы улучшает ее читаемость.
Наследование интерфейса, полиморфизм
Наследование типа и полиморфизм обеспечиваются наследованием интерфейса. Пример :
Результат выполнения программы:
Таким образом, концепция интерфейсов добавляет полиморфизму второе измерение :
- Иерархический полиморфизм в стиле C++, основанный на приведении к базовому типу классов и/или интерфейсов (см. TestShips);
- Полиморфизм экземпляров, основанный на разных реализациях одного и того же интерфейса (см. INumber).
Наследование имеет два аспекта:
- "быть похожим на" - наследование типа, поведения;
- "быть устроенным как" - наследование реализации.
Наследование реализации не означает наследование типа! В практике это не встречается, потому что и в С++ и в Java невозможно наследование реализации без наследования интерфейса. В C++ интерфейс и класс неотделимы друг от друга. В Java интерфейс от класса отделить можно, но класс от интерфейса - нельзя.
В С++ и в Java совокупность общедоступных (public) методов неявно образует интерфейс данного класса. В силу этого наследование класса автоматически означает как наследование реализации, так и наследование интерфейса (типа). Очевидно, что наследование структуры данных и программного кода не определяет тип потомка. Например, абстрактные методы являются частью интерфейса и не являются частью реализации. Если бы можно было исключить их из наследования, то мы получили бы наследование реализации без сохранения типа.
Представьте себе будущее, где автомобилями управляют компьютеры без участия человека. Производители автомобилей пишут программное обеспечение (на Java, конечно ? ), которое управляет машиной — остановиться, поехать, повернуть и т.д. Другие разработчики делают системы, которые принимают данные GPS (Global Positioning System) и используют эти данные для управления автомобилем. Производители автомобилей публикуют интерфейс-стандарт, который описывает методы для управления машиной. Таким образом сторонние разработчики могут знать какие методы вызывать, чтобы заставить автомобиль двигаться, а производители автомобилей могут изменять внутреннюю реализацию своего продукта в любое время. Ни одна из групп разработчиков не знает как написаны их программы.
Интерфейсы Java
Интерфейсы в Java во многом напоминают классы, но могут содержать только константы, сигнатуры методов и вложенные типы. В интерфейсах нет описания методов. Нельзя создать объект типа интерфейса (но можно использовать в качестве типа — интерфейсные ссылки, об этом позже) — интерфейсы могут только реализовываться некоторым классом или наследоваться другим интерфейсом. Объявление интерфейса очень похоже на объявление класса:
Сигнатуры методов объявляются без скобок и заканчиваются точкой с запятой. Для использования интерфейса вы должны написать класс, который будет реализовывать ваш интерфейс. Класс который реализует интерфейс, должен описывать все методы, объявленные в интерфейсе. Например:
В примере выше — производители автомобилей пишут программное обеспечение каждый по-своему, но с одинаковым интерфейсом. Сторонние разработчики — клиенты интерфейса, могут писать собственно ПО с использованием методов, объявленных в интерфейсе.
Интерфейсы в качестве API
Пример с автомобилями показывает как интерфейсы могут использоваться в качестве API (Application Programming Interface) или интерфейса программирования приложений. Использование API — обычная практика при разработке коммерческого ПО. Обычно компании-разработчики продают программное обеспечение, содержащее набор методов, которые другие компании хотят использовать в своих продуктах.
Интерфейсы и множественное наследование
Интерфейсы играют еще одну важную роль в языке программировния Java. Java не разрешает множественного наследования, но интерфейсы предоставляют альтернативу. В Java класс может наследовать только один класс, но может реализовывать много интерфейсов. Таким образом объекты могут иметь несколько типов: тип их собственного класса и типы всех реализуемых интерфейсов. При создании объектов класса в качестве типа может указываться имя реализованного в классе интерфейса. Другими словами, если класс реализует интерфейс, то ссылку на объект этого класса можно присвоить интерфейсной переменной — переменной, в качестве типа которой указано имя соответствующего интерфейса.
Объявление интерфейса
Объявление интерфейса содержит ключевое слово interface , имя интерфейса, список родительских интерфейсов через запятую (если есть) и тело интерфейса. Например:
Модификатор доступа public означает что интерфейс может быть использован любым классом в любом пакете. Если не определить интерфейс как публичный, он будет доступен только в рамках своего пакета. Интерфейс может наследовать другие интерфейсы, как классы могут наследовать другой класс. В отличие от классов, интерфейсы могут наследовать любое количество других интерфейсов.
Реализация интерфейса
Для объявления класса, реализующего интерфейс, вы должны использовать ключевое слово implements после которого перечисляются интерфейсы.
Класс может реализовывать много интерфейсов. Объявление реализуемых интерфейсов идет после объявления наследуемого ( extends ) класса (если есть).
Пример простого интерфейса
Рассмотрим интерфейс, который определяет метод для сравнения объектов.
Чтобы иметь возможность сравнивать объекты мы должны реализовать интерфейс Relatable . Любой класс может реализовать интерфейс Relatable , если есть способ сравнить объекты. Для строк сравнивать можно количество символов, для книг — количество страниц, для студентов — вес и т.д. Для плоских геометрических фигур отличной характеристикой будет площадь, для трехмерных — объем. Все эти классы могут реализовать метод isLargerThan() . Если вы знаете, что класс реализует интерфейс Relatable , то вы смело можете сравнивать объекты этого класса.
Реализация интерфейса Relatable
Напишем класс Rectangle , реализующий интерфейс Relatable .
Так как класс RectanglePlus реализует Relatable , размеры любых двух объектов типа RectanglePlus можно сравнивать.
Метод isLargerThan в качестве аргумента принимает объекты типа Relatable . При реализации метода в примере выше мы используем приведение типов, потому что компилятор не поймет что, other — объект типа RectanglePlus и вызов метода other.getArea() без приведения типов приведет к ошибке.
Использование интерфейса в качестве типа
Когда вы объявляете интерфейс, вы объявляете новый ссылочный тип данных. Вы можете использовать название интерфейса в качестве типа данных так же как и любые другие типы. Если вы объявляете переменную типа интерфеса, то вы можете можете присвоить ей объект любого класса, который реализует этот интерфейс.
Рассмотрим пример — метод, который ищет больший объект из двух любых объектов, класс которых реализует интерфейс Relatable :
Приведением object1 к типу Relatable , мы делаем возможным вызов метода isLargerThan .
Так же для любого класса, реализующего интерфес Relatable, можно реализвать методы:
Переопределение интерфейсов
Допустим, вы написали интерфейс DoIt :
Предположим, позже, вы захотели добавить в него третий метод:
Если вы сделаете это изменение, то все классы, реализующие этот интерфейс сломаются, т.к. они перестанут его реализовывать.
Старайтесь избегать подобных изменений и продумывать интерфейс полностью изначально. Но часто на практике это невозможно и выходом из этой ситуации может быть определение нового интерфейса DoItPlus , который расширяет DoIt :
Теперь пользователи вашего интерфейса смогут перейти к использованию нового интерфейса или остаться со старым без боли.
Интерфейсы Java созданы для поддержки динамического выбора (resolution) методов во время выполнения программы. Интерфейсы похожи на классы, но в отличие от последних у интерфейсов нет переменных представителей, а в объявлениях методов отсутствует реализация. Класс может иметь любое количество интерфейсов. Все, что нужно сделать — это реализовать в классе полный набор методов всех интерфейсов. Сигнатуры таких методов класса должны точно совпадать с сигнатурами методов реализуемого в этом классе интерфейса. Интерфейсы обладают своей собственной иерархией, не пересекающейся с классовой иерархией наследования. Это дает возможность реализовать один и тот же интерфейс в различных классах, никак не связанных по линии иерархии классового наследования. Именно в этом и проявляется главная сила интерфейсов.
Интерфейс — это структура данных, которая может содержать поля, представленные в виде именованных констант (ключевое слово final тут обычно не указывается, так как поля — это всегда именованные константы) и объявления методов. Интерфейсом могут расширяться многие классы. Интерфейс может сам расширяться несколькими интерфейсами. Заметим, что интерфейс могут использовать сразу несколько классов, независимых друг от друга.
У интерфейса могут быть следующие модификаторы.
• public (если он есть, то интерфейс доступен отовсюду, если его нет — доступен только в данном пакете).
• abstract (так как интерфейс всегда абстрактный, то модификатор обычно опускается).
• strictfp— все позже реализуемые методы должны будут работать с числами с плавающей точкой аналогично на всех машинах Java.
Приведем пример простого интерфейса, а также класса, который его наследует (листинг 4.13).
Листинг 4.13.
Пример простого интерфейса и класса, который его наследует
Интерфейс является ссылочным типом в Java. Это похоже на класс. Это коллекция абстрактных методов. Класс реализует интерфейс, таким образом наследуя абстрактные методы интерфейса.
Наряду с абстрактными методами интерфейс может также содержать константы, методы по умолчанию, статические методы и вложенные типы. Тела методов существуют только для стандартных методов и статических методов.
Написание интерфейса похоже на написание класса. Но класс описывает атрибуты и поведение объекта. И интерфейс содержит поведения, которые реализует класс.
Если класс, реализующий интерфейс, не является абстрактным, все методы интерфейса должны быть определены в классе.
Интерфейс похож на класс в следующих отношениях —
Интерфейс может содержать любое количество методов.
Интерфейс записывается в файл с расширением .java , имя интерфейса которого совпадает с именем файла.
Байт-код интерфейса появляется в файле .class .
Интерфейсы появляются в пакетах, и соответствующий им файл байт-кода должен находиться в структуре каталогов, соответствующей имени пакета.
Интерфейс может содержать любое количество методов.
Интерфейс записывается в файл с расширением .java , имя интерфейса которого совпадает с именем файла.
Байт-код интерфейса появляется в файле .class .
Интерфейсы появляются в пакетах, и соответствующий им файл байт-кода должен находиться в структуре каталогов, соответствующей имени пакета.
Тем не менее, интерфейс отличается от класса в нескольких отношениях, в том числе —
Вы не можете создать экземпляр интерфейса.
Интерфейс не содержит конструкторов.
Все методы в интерфейсе являются абстрактными.
Интерфейс не может содержать поля экземпляра. Единственные поля, которые могут появиться в интерфейсе, должны быть объявлены как static, так и final.
Интерфейс не расширен классом; это реализуется классом.
Интерфейс может расширять несколько интерфейсов.
Вы не можете создать экземпляр интерфейса.
Интерфейс не содержит конструкторов.
Все методы в интерфейсе являются абстрактными.
Интерфейс не может содержать поля экземпляра. Единственные поля, которые могут появиться в интерфейсе, должны быть объявлены как static, так и final.
Интерфейс не расширен классом; это реализуется классом.
Интерфейс может расширять несколько интерфейсов.
Объявление интерфейсов
Ключевое слово interface используется для объявления интерфейса. Вот простой пример объявления интерфейса:
пример
Ниже приведен пример интерфейса —
/* File name : NameOfInterface.java */ import java . lang .*; // Any number of import statements public interface NameOfInterface < // Any number of final, static fields // Any number of abstract method declarations\ >
Интерфейсы имеют следующие свойства —
Интерфейс неявно абстрактный. Вам не нужно использовать ключевое слово abstract при объявлении интерфейса.
Каждый метод в интерфейсе также неявно абстрактный, поэтому ключевое слово abstract не требуется.
Методы в интерфейсе неявно общедоступны.
Интерфейс неявно абстрактный. Вам не нужно использовать ключевое слово abstract при объявлении интерфейса.
Каждый метод в интерфейсе также неявно абстрактный, поэтому ключевое слово abstract не требуется.
Методы в интерфейсе неявно общедоступны.
пример
Реализация интерфейсов
Когда класс реализует интерфейс, вы можете думать о классе как о подписании контракта, соглашающегося выполнять определенное поведение интерфейса. Если класс не выполняет все поведения интерфейса, класс должен объявить себя абстрактным.
Класс использует ключевое слово Implements для реализации интерфейса. Ключевое слово Implements появляется в объявлении класса после расширенной части объявления.
пример
Это даст следующий результат —
Выход
При переопределении методов, определенных в интерфейсах, необходимо соблюдать несколько правил:
Проверенные исключения не должны объявляться в методах реализации, отличных от тех, которые объявлены методом интерфейса, или подклассов тех, которые объявлены методом интерфейса.
Сигнатура метода интерфейса и того же возвращаемого типа или подтипа должна сохраняться при переопределении методов.
Сам класс реализации может быть абстрактным, и если это так, методы интерфейса не должны быть реализованы.
Проверенные исключения не должны объявляться в методах реализации, отличных от тех, которые объявлены методом интерфейса, или подклассов тех, которые объявлены методом интерфейса.
Сигнатура метода интерфейса и того же возвращаемого типа или подтипа должна сохраняться при переопределении методов.
Сам класс реализации может быть абстрактным, и если это так, методы интерфейса не должны быть реализованы.
При реализации интерфейсов существует несколько правил —
Класс может реализовывать более одного интерфейса одновременно.
Класс может расширять только один класс, но реализовывать множество интерфейсов.
Интерфейс может расширять другой интерфейс, аналогично тому, как класс может расширять другой класс.
Класс может реализовывать более одного интерфейса одновременно.
Класс может расширять только один класс, но реализовывать множество интерфейсов.
Интерфейс может расширять другой интерфейс, аналогично тому, как класс может расширять другой класс.
Расширение интерфейсов
Интерфейс может расширять другой интерфейс так же, как класс может расширять другой класс. Ключевое слово extends используется для расширения интерфейса, а дочерний интерфейс наследует методы родительского интерфейса.
Следующий интерфейс Sports расширен интерфейсами Hockey и Football.
пример
Интерфейс Hockey имеет четыре метода, но он наследует два от Sports; таким образом, класс, который реализует Хоккей, должен реализовать все шесть методов. Точно так же класс, который реализует Football, должен определить три метода из Football и два метода из Sports.
Расширение нескольких интерфейсов
Класс Java может расширять только один родительский класс. Многократное наследование не допускается. Однако интерфейсы не являются классами, и интерфейс может расширять несколько родительских интерфейсов.
Ключевое слово extends используется один раз, а родительские интерфейсы объявляются в списке через запятую.
Например, если интерфейс Hockey расширяет как Sports, так и Event, он будет объявлен как —
пример
Интерфейсы тегов
Наиболее распространенное использование расширяемых интерфейсов происходит, когда родительский интерфейс не содержит никаких методов. Например, интерфейс MouseListener в пакете java.awt.event расширяет java.util.EventListener, который определяется как —
пример
Интерфейс без методов называется интерфейсом тегирования . Существует две основные цели разработки интерфейсов тегирования —
Создает общего родителя. Как и в случае интерфейса EventListener, который расширяется десятками других интерфейсов в Java API, вы можете использовать интерфейс тегов для создания общего родителя среди группы интерфейсов. Например, когда интерфейс расширяет EventListener, JVM знает, что этот конкретный интерфейс будет использоваться в сценарии делегирования события.
Добавляет тип данных в класс. В этой ситуации используется термин тегирование. Класс, который реализует интерфейс тегирования, не должен определять какие-либо методы (поскольку у интерфейса их нет), но класс становится типом интерфейса посредством полиморфизма.
Читайте также: