Что такое интерфейсы Java 8 и как их использовать?
В Java интерфейс функционирует почти так же, как абстрактный класс, что означает, что объект никогда не может быть создан из интерфейса. В результате у интерфейса нет конструкторов, но есть методы.
До Java 8 интерфейс мог описывать операции, которые выполняет его реализующий класс, но не то, как реализующий класс должен выполнять эту операцию (подробнее об этом позже). Теперь с Java 8 разработчик может делать и то, и другое с помощью интерфейса.
Это связано с тем, что в Java 8 были введены методы интерфейса по умолчанию. Таким образом, разработчики теперь имеют возможность использовать традиционные абстрактные методы, а также новые конкретные методы в интерфейсе. Давайте рассмотрим подробнее.
Что такое интерфейс?
Прежде чем вы сможете по-настоящему понять назначение интерфейса и способы его эффективного использования, вам необходимо понять полиморфизм. Полиморфизм – это основная концепция объектно-ориентированного программирования, которая позволяет разработчику создавать обобщенное и специализированное поведение с классами (которые в некоторых случаях не связаны напрямую).
Основное преимущество полиморфизма заключается в том, что он облегчает повторное использование кода, что жизненно важно в современной индустрии разработки программного обеспечения.
Итак, как полиморфизм соотносится с интерфейсом Java? В Java интерфейс позволяет классам, которые не были бы условно связаны, иметь доступ к аналогичным операциям. В своей простейшей форме интерфейс Java – это шаблон, который может быть легко использован различными классами, реализующими его. Эти реализующие классы могут затем преобразовать метод интерфейса из его обобщенного состояния в более специализированное состояние для выполнения конкретной задачи.
Каковы преимущества использования интерфейсов Java 8?
Наиболее очевидным преимуществом использования интерфейса Java 8 является его новая возможность использования конкретных методов.
Еще одно приятное преимущество интерфейсов Java 8 – это возможность добавлять новые конкретные методы к существующему интерфейсу, который уже был реализован, без нарушения работы программы. До Java 8, если у вас был класс, реализующий интерфейс, но не использующий все его методы, этот класс нужно было бы пометить как абстрактный. Иначе программа сломалась бы.
Когда следует использовать интерфейс?
Многие существующие программы потенциально могут использовать интерфейсы Java 8. Функция интерфейса – облегчить жизнь программисту. Хотя та же функциональность может быть достигнута без интерфейсов, их использование сделает ваши программы более организованными, а процесс разработки – менее трудоемким.
Если вы знакомы с наследованием, вы должны знать, что это также основная концепция объектно-ориентированного программирования, облегчающая обобщение. При наследовании похожие классы группируются по родительско-дочерним отношениям.
Благодаря полиморфизму (который является программным поведением, которое демонстрирует интерфейс) классы, которые обычно не имеют доступа к одним и тем же методам (из-за отсутствия отношений родитель-потомок), теперь могут обрабатываться полиморфно.
Практический пример использования интерфейса – в бухгалтерии компании-разработчика программного обеспечения. Этот отдел, скорее всего, будет использовать набор одних и тех же методов (или операций) при создании платежной ведомости сотрудника и счета-фактуры клиента.
Это два класса, которые нельзя было бы связывать условно, но теперь они могут использовать одни и те же операции благодаря интерфейсам Java 8.
Создание интерфейса на Java
Используя приведенный выше сценарий бухгалтерии, вы можете создать интерфейс, который имеет дело с платежными операциями. Назначение этого интерфейса – помочь в создании отчетов об оплате (в форме счетов-фактур, расчетных ведомостей и других расходов).
Создание примера интерфейса Java
//Java interface
public interface Payable {
//abstract method public void paymentAmount();
}
Приведенный выше код генерирует простой интерфейс Java. Ключевое слово interface указывает, что Payable – это интерфейс, а метод paymentAmount () – абстрактный метод, поскольку он не реализован.
Реализация примера интерфейса Payable
public class Employee implements Payable {
//attributes
private String name; private String position;
//primary constructor
public Employee (String name, String position) {
this.name = name; this.position = position;
}
//payLevel method - takes an employee's position and returns their pay
public double payLevel(String position) {
position.toLowerCase();
if (position == "junior" ) {
return 10.00;
}
if(position == "mid-level") {
return 20.0;
}
if(position == "senior") {
return 30.00;
}
return 0 ;
}
@Override public void paymentAmount() {
//passes the position attribute provided by the user to the payLevel() method above
// store the return from the function call to a double variable called pay
//and print the relevant data to the console
double pay = payLevel(position);
System.out.println(name + " pay for this month is: " + pay);
}
}
Чтобы использовать интерфейс в классе, вам сначала нужно реализовать этот интерфейс с помощью ключевого слова реализации , как вы можете видеть в приведенном выше коде. После реализации нового интерфейса вы должны создать конкретные методы для всех абстрактных методов в интерфейсе, используя ключевое слово @Override .
Выполнение примера программы
public class Main {
public static void main(String[] args) {
//Create a new employee pay report
Payable JanesPay = new Employee ("Jane Doe", "mid-level");
//calculate the employee's pay
JanesPay.paymentAmount();
}
}
В приведенной выше программе класс Employee используется для создания новой расчетной ведомости с использованием интерфейса Payable . Объект не может быть создан из интерфейса, но объект может быть объявлен с помощью интерфейса, как вы можете видеть в приведенном выше коде.
Объект оплаты Джейн создается с использованием двух атрибутов – имени сотрудника и должности сотрудника в компании. В классе сотрудника есть только один основной конструктор, поэтому каждый новый созданный объект сотрудника должен иметь два строковых атрибута.
Используя объект pay Джейн , программа вызывает метод paymentAmount () в классе сотрудника , который выдает в консоли следующий вывод:
Jane Doe pay for this month is: 20.0
Реализация интерфейса Payable на примере клиента
public class Customer implements Payable{
private String customerName;
private String projectType;
public Customer(String customerName, String projectType) {
this.customerName = customerName;
this.projectType = projectType;
}
public double customerInvoice(String projectType) {
projectType.toLowerCase();
if (projectType == "small" ) {
return 10.00;
}
if(projectType == "medium") {
return 20.0;
}
if(projectType == "large") {
return 30.00;
}
return 0 ;
}
@Override public void paymentAmount() {
double total = customerInvoice(projectType);
System.out.println(customerName + " total charge for services provided is: " + total);
}
}
Классы сотрудников и клиентов не связаны друг с другом, но поскольку каждый из них реализует один и тот же интерфейс, теперь у них есть доступ к аналогичным операциям. Как и класс сотрудника, класс клиента должен реализовать интерфейс и переопределить абстрактный метод paymentAmount () для правильной работы.
Теперь те же операции, которые проводились с объектом класса служащего , можно также проводить с объектом класса клиента .
Создание примера объекта клиента
public class Main {
public static void main(String[] args) {
//Create a new customer invoice report
Payable PaulsInvoice = new Customer("Paul Smith", "large");
//calculate the customer's pay
PaulsInvoice.paymentAmount();
}
}
Приведенный выше код генерирует в консоли следующий вывод:
Paul Smith total charge for services provided is: 30.0
Поскольку интерфейс является интерфейсом Java 8, вы можете добавить к нему методы по умолчанию, не нарушая код, как вы можете видеть в примере ниже.
Обновление примера интерфейса Java 8
//Java interface
public interface Payable {
//abstract method
public abstract void paymentAmount();
//concrete method
public default void companyName() {
System.out.println("Software Company");
}
}
До Java 8 добавление к интерфейсу конкретного метода из приведенного выше кода приводило к поломке интерфейса. Это связано с тем, что интерфейсы до Java 8 не могли иметь конкретных методов. Однако, если бы метод был абстрактным, интерфейс остался бы неизменным. Но классы, которые реализовали это до добавления нового метода, сломались.
Теперь, благодаря Java 8, добавление конкретных методов в интерфейс не приведет к нарушению уже реализованных классов. Следовательно, объекты, созданные из любого из двух реализующих классов в этом примере управления учетной записью, могут использовать метод companyName () без изменения своего существующего кода.
Пример использования метода по умолчанию для интерфейса Java 8
public class Main {
public static void main(String[] args) {
//Create a new employee pay report
Payable JanesPay = new Employee("Jane Doe", "mid-level");
//call the default method from the interface
JanesPay.companyName();
//calculate the employee's pay
JanesPay.paymentAmount();
}
}
Приведенный выше код выдаст в консоли следующее:
Software Company
Jane Doe pay for this month is: 20.0
Использование обобщения для создания повторно используемого кода
Теперь вы можете использовать аналогичные операции для классов, которые условно не связаны с помощью интерфейсов Java 8. У вас также есть возможность и знания использовать как конкретные, так и абстрактные методы в ваших интерфейсах.
Но для классов, которые традиционно связаны, вы можете узнать, как повторно использовать код с наследованием.