Default и Static методы в интерфейсах
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 37 из 87.
Изначально интерфейсы могли содержать только абстрактные методы без реализации. Начиная с Java 8, интерфейсы получили возможность включать методы по умолчанию и статические методы, что сделало их более гибкими.
Метод по умолчанию предоставляет реализацию непосредственно в интерфейсе с использованием ключевого слова default. Классы, реализующие интерфейс, автоматически наследуют это поведение, но при необходимости могут его переопределить:
public interface Drawable {
void draw();
default void display() {
System.out.println("Displaying on screen...");
draw();
}
}Любой класс, реализующий Drawable, получает метод display() «бесплатно». Это особенно полезно для добавления новых методов в существующие интерфейсы без нарушения работы классов, которые их уже реализуют.
Статические методы в интерфейсах работают так же, как статические методы в классах. Они принадлежат самому интерфейсу и вызываются с использованием имени интерфейса:
public interface MathOperations {
static int add(int a, int b) {
return a + b;
}
}
// Использование
int result = MathOperations.add(5, 3);Статические методы интерфейса не могут быть переопределены и не наследуются реализующими классами. Они полезны для вспомогательных методов, связанных с назначением интерфейса.
Если класс реализует два интерфейса с одинаковой сигнатурой метода по умолчанию, класс должен переопределить этот метод, чтобы разрешить конфликт.
Задание
ЛегкоДавайте создадим систему обмена сообщениями, которая демонстрирует использование методов по умолчанию (default) и статических (static) методов в интерфейсах. Вы создадите интерфейс со встроенной функциональностью, которую реализующие классы смогут использовать напрямую или настраивать по мере необходимости.
Вы организуете свой код в четырех файлах:
Messenger.java: Определите интерфейс, представляющий любую службу обмена сообщениями. Он должен объявлять абстрактный методsendMessage(String message), который возвращает void. Добавьте метод по умолчанию с именемsendWithTimestamp(String message), который выводит:[TIMESTAMP], после чего вызываетsendMessage(message). Также включите статический метод с именемformatMessage(String message), который возвращает сообщение, преобразованное в верхний регистр.EmailMessenger.java: Создайте класс, реализующийMessenger. У него есть полеrecipient(String). Включите конструктор для инициализации получателя. РеализуйтеsendMessage()для вывода:Email to [recipient]: [message]. Этот класс использует метод по умолчаниюsendWithTimestamp()как есть.SMSMessenger.java: Создайте еще один класс, реализующийMessenger. У него есть полеphoneNumber(String). Включите конструктор для инициализации номера телефона. РеализуйтеsendMessage()для вывода:SMS to [phoneNumber]: [message]. Переопределите метод по умолчаниюsendWithTimestamp(), чтобы он выводил:[URGENT], а затем вызывалsendMessage(message)вместо использования поведения по умолчанию с меткой времени.Main.java: Объедините все вместе, чтобы продемонстрировать методы интерфейса по умолчанию и статические методы. Вы получите три входных значения: получателя электронной почты, номер телефона и сообщение. Сначала используйте статический методMessenger.formatMessage(), чтобы отформатировать сообщение и сохранить его. Затем создайте EmailMessenger и SMSMessenger. Для каждого мессенджера вызовитеsendWithTimestamp()с отформатированным сообщением — обратите внимание, как EmailMessenger использует реализацию по умолчанию, в то время как SMSMessenger использует свою переопределенную версию.
Вы получите три входных значения: получателя электронной почты (String), номер телефона (String) и сообщение (String).
Ваш вывод должен содержать всего четыре строки — по две для каждого мессенджера. EmailMessenger покажет префикс метки времени по умолчанию, а SMSMessenger покажет свой собственный префикс срочности. Оба будут использовать статически отформатированное сообщение (в верхнем регистре)!
Шпаргалка
Начиная с Java 8, интерфейсы могут включать методы по умолчанию и статические методы в дополнение к абстрактным методам.
Методы по умолчанию предоставляют реализацию непосредственно в интерфейсе с использованием ключевого слова default. Классы, реализующие интерфейс, наследуют это поведение автоматически, но при необходимости могут его переопределить:
public interface Drawable {
void draw();
default void display() {
System.out.println("Displaying on screen...");
draw();
}
}Статические методы в интерфейсах принадлежат самому интерфейсу и вызываются с использованием имени интерфейса. Они не могут быть переопределены и не наследуются реализующими классами:
public interface MathOperations {
static int add(int a, int b) {
return a + b;
}
}
// Использование
int result = MathOperations.add(5, 3);Если класс реализует два интерфейса с одинаковой сигнатурой метода по умолчанию, класс должен переопределить этот метод, чтобы разрешить конфликт.
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Чтение входных данных
String emailRecipient = scanner.nextLine();
String phoneNumber = scanner.nextLine();
String message = scanner.nextLine();
// TODO: Используйте Messenger.formatMessage() для форматирования сообщения и сохраните его
// TODO: Создайте EmailMessenger с получателем электронной почты
// TODO: Создайте SMSMessenger с номером телефона
// TODO: Вызовите sendWithTimestamp() для EmailMessenger с отформатированным сообщением
// TODO: Вызовите sendWithTimestamp() для SMSMessenger с отформатированным сообщением
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»