1. Обзор
В этом уроке мы поговорим об интерфейсах в Java. Мы также увидим, как Java использует их для реализации полиморфизма и множественного наследования.
2. Что такое интерфейсы в Java?
В Java интерфейс — это абстрактный тип, содержащий набор методов и переменных-констант. Это одна из основных концепций Java, которая используется для достижения абстракции, полиморфизма и множественного наследования .
Давайте посмотрим на простой пример интерфейса на Java:
public interface Electronic {
// Constant variable
String LED = "LED";
// Abstract method
int getElectricityUse();
// Static method
static boolean isEnergyEfficient(String electtronicType) {
if (electtronicType.equals(LED)) {
return true;
}
return false;
}
//Default method
default void printDescription() {
System.out.println("Electronic Description");
}
}
Мы можем реализовать интерфейс в классе Java, используя ключевое
слово Implements.
Далее давайте также создадим класс Computer
, который реализует только что созданный электронный
интерфейс:
public class Computer implements Electronic {
@Override
public int getElectricityUse() {
return 1000;
}
}
2.1. Правила создания интерфейсов
В интерфейсе нам разрешено использовать:
Мы также должны помнить, что:
- мы не можем создавать интерфейсы напрямую
- интерфейс может быть пустым, без методов или переменных.
- мы не можем использовать
последнее
слово в определении интерфейса, так как это приведет к ошибке компилятора - все объявления интерфейсов должны иметь модификатор доступа
public
или default;абстрактный
модификатор будет автоматически добавлен компилятором - метод интерфейса не может быть
защищенным
илиокончательным
- вплоть до Java 9 методы интерфейса не могли быть
закрытыми
; однако в Java 9 появилась возможность определять частные методы в интерфейсах . - переменные интерфейса являются
общедоступными
,статическими
иокончательными
по определению; нам не разрешено изменять их видимость
3. Чего мы можем достичь, используя их?
3.1. Поведенческая функциональность
Мы используем интерфейсы для добавления определенных поведенческих функций, которые могут использоваться несвязанными классами. Например, Comparable
, Comparator
и Cloneable
— это интерфейсы Java, которые могут быть реализованы несвязанными классами. Ниже приведен пример интерфейса Comparator
` , который используется для сравнения двух экземпляров класса
Employee` :
public class Employee {
private double salary;
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
public class EmployeeSalaryComparator implements Comparator<Employee> {
@Override
public int compare(Employee employeeA, Employee employeeB) {
if (employeeA.getSalary() < employeeB.getSalary()) {
return -1;
} else if (employeeA.getSalary() > employeeB.getSalary()) {
return 1;
} else {
return 0;
}
}
}
Для получения дополнительной информации посетите наш учебник по Comparator
и Comparable
в Java.
3.2. Множественное наследство
Классы Java поддерживают сингулярное наследование. Однако, используя интерфейсы, мы также можем реализовать множественное наследование.
Например, в приведенном ниже примере мы замечаем, что класс Car
` реализует интерфейсы
Fly и
Transform .Таким образом, он наследует методы
fly и
transform` :
public interface Transform {
void transform();
}
public interface Fly {
void fly();
}
public class Car implements Fly, Transform {
@Override
public void fly() {
System.out.println("I can Fly!!");
}
@Override
public void transform() {
System.out.println("I can Transform!!");
}
}
3.3. Полиморфизм
Начнем с вопроса: что такое полиморфизм ? Это способность объекта принимать различные формы во время выполнения. Чтобы быть более конкретным, это выполнение метода переопределения, связанного с определенным типом объекта во время выполнения.
В Java мы можем добиться полиморфизма с помощью интерфейсов. Например, интерфейс формы
может принимать разные формы — это может быть круг
или квадрат.
Начнем с определения интерфейса Shape :
public interface Shape {
String name();
}
Теперь также создадим класс Circle :
public class Circle implements Shape {
@Override
public String name() {
return "Circle";
}
}
А также класс Square :
public class Square implements Shape {
@Override
public String name() {
return "Square";
}
}
Наконец, пришло время увидеть полиморфизм в действии, используя наш интерфейс Shape и его реализации.
Давайте создадим несколько объектов Shape
, добавим их в список и
,
наконец, напечатаем их имена в цикле:
List<Shape> shapes = new ArrayList<>();
Shape circleShape = new Circle();
Shape squareShape = new Square();
shapes.add(circleShape);
shapes.add(squareShape);
for (Shape shape : shapes) {
System.out.println(shape.name());
}
4. Методы по умолчанию в интерфейсах
Традиционные интерфейсы в Java 7 и более ранних версиях не обеспечивают обратной совместимости.
Это означает, что если у вас есть устаревший код, написанный на Java 7 или более ранней версии, и вы решили добавить абстрактный метод к существующему интерфейсу, то все классы, реализующие этот интерфейс, должны переопределить новый абстрактный метод . В противном случае код сломается.
Java 8 решила эту проблему, представив метод по умолчанию, который является необязательным и может быть реализован на уровне интерфейса.
5. Правила наследования интерфейса
Чтобы добиться множественного наследования через интерфейсы, мы должны помнить несколько правил. Давайте рассмотрим это подробно.
5.1. Интерфейс, расширяющий другой интерфейс
Когда интерфейс расширяет
другой интерфейс, он наследует все абстрактные методы этого интерфейса. Начнем с создания двух интерфейсов, HasColor
и Shape
:
public interface HasColor {
String getColor();
}
public interface Box extends HasColor {
int getHeight()
}
В приведенном выше примере Box
наследуется от HasColor
с помощью ключевого слова extends.
Таким образом, интерфейс Box
наследует getColor
. В результате интерфейс Box
теперь имеет два метода: getColor
и getHeight
.
5.2. Абстрактный класс, реализующий интерфейс
Когда абстрактный класс реализует интерфейс, он наследует все его абстрактные методы и методы по умолчанию. Рассмотрим интерфейс Transform и реализующий его
абстрактный
класс Vehicle
:
public interface Transform {
void transform();
default void printSpecs(){
System.out.println("Transform Specification");
}
}
public abstract class Vehicle implements Transform {}
В этом примере класс Vehicle
наследует два метода: метод абстрактного преобразования и метод
printSpecs
по умолчанию .
6. Функциональные интерфейсы
С самого начала у Java было много функциональных интерфейсов, таких как Comparable
(начиная с Java 1.2) и Runnable
(начиная с Java 1.0).
В Java 8 появились новые функциональные интерфейсы, такие как Predicate
, Consumer
и Function
. Чтобы узнать больше об этом, посетите наш учебник по функциональным интерфейсам в Java 8 .
7. Заключение
В этом руководстве мы дали обзор интерфейсов Java и рассказали, как их использовать для достижения полиморфизма и множественного наследования.
Как всегда, полные образцы кода доступны на GitHub.