Интерфейсы в Java и немного о полиморфизме

Что такое интерфейс Java и каким он бывает. Что такое функциональный интерфейс. Разбираем на примерах.
17 ноября 2017Cbc0f0509128ea8a7487ec71c1240fb531db396bМария Лисянская2152714

Интерфейс – это контракт, в рамках которого части программы, зачастую написанные разными людьми, взаимодействуют между собой и со внешними приложениями. Интерфейсы работают со слоями сервисов, безопасности, DAO и т.д. Это позволяет создавать модульные конструкции, в которых для изменения одного элемента не нужно трогать остальные.

Новички часто спрашивают, чем интерфейс отличается  от абстрактного класса. Интерфейсы в Java компенсируют отсутствие множественного наследования классов. У класса-потомка может быть только один абстрактный класс-родитель, а вот интерфейсов класс может применять (имплементировать) сколько угодно.

Интерфейс на Java объявляют примерно так же, как и класс:

public interface MyInterface {

  void do_something(){
    // ...
  }

  default void say_goodbye(String userName) {
    System.out.println("Пока, "+userName+"! Заходи ещё.");
  }

}

В имплементирующем интерфейс классе должны быть реализованы все предусмотренные интерфейсом методы, за исключением методов по умолчанию.

Методы по умолчанию  впервые появились в Java 8. Их  обозначают модификатором default. В нашем примере это метод say_goodbye, реализация которого прописана прямо в интерфейсе. Дефолтные методы изначально готовы к использованию, но при необходимости их можно переопределять в применяющих интерфейс классах.

Функциональный интерфейс Java

Если у интерфейса только один абстрактный метод, перед нами функциональный интерфейс. Его принято помечать аннотацией @FunctionalInterface, которая указывает компилятору, что при обнаружении второго абстрактного метода в этом интерфейсе нужно сообщить об ошибке. Стандартных (default) методов у интерфейса может быть множество – в том числе принадлежащих классу java.lang.Object.

Как выглядит функциональный интерфейс на Java:

@FunctionalInterface
public interface GaMechanic {
void new_deck();
default int deal_cards(int num_of_players)
{
// тело метода
}
default int check_your_cards(int[] hand)
{
//...
}
default int battle(Card player1_Card, Card player2_Card)
{
//...
}
} 

Функциональные интерфейсы появились в Java 8. Они обеспечили поддержку лямбда-выражений, использование которых делает код лаконичным и понятным:

button.setOnAction(event -> // если происходит событие
   System.out.println("Обрабатываем нажатие кнопки."));

В той же версии появились пакеты встроенных интерфейсов: java.util.function и java.util.stream.  

Реализация интерфейсов классами Java

Допустим, есть интерфейс Edible, которым пользуются классы Fruit, Vegetable, Fish. Экземпляры этих классов можно создавать так:

Edible a1 = new Fruit("Яблоко", “Антоновка”);
Edible a2 = new Fish("Нерка слабосолёная", “Тихий океан”, 150);

Хорошим тоном считается давать интерфейсам названия с окончанием -able/-ible  —  это показывает, что с объектами, имплементирующими интерфейс, можно что-то делать: Edible (можно есть), Moveable (можно двигать), Clickable (реагирует на клик) и т.д.

Обратите внимание на разницу в конструкторах: для фруктов задаём название и сорт, для рыбы – название, район вылова и вес порции в граммах. Но ссылки на оба объекта храним в переменных одного типа – «Съестное».

Интерфейсы и полиморфизм

Пример выше иллюстрирует один из трех основополагающих принципов ООП  —   полиморфизм. Мы раскрыли одно и то же явление  —  съедобность  —  через несколько классов, свойства и методы которых частично отличаются. Представление разных форм одного явления  —  это и есть полиморфизм. Если нужно, такую систему всегда можно расширить и скорректировать. В нашем случае  —  добавить новые виды съестного и методы их приготовления.

В Java полиморфизм можно реализовать через:

  • наследование — с переопределением параметров и методов базового класса;
  • абстрактные классы — шаблоны для раздельной реализации в разных классах;
  • интерфейсы — для имплементации классами.

Интерфейс выручает  в ситуации, когда при создании переменной мы не знаем, объект какого класса ей будет присвоен.

Новые комментарии