Результат выполнения кода в методе main:
"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" -Didea.launcher.port=54625 "
printing::test
printing from class ::test
printing::default part included
Process finished with exit code 0
Как видно, даже в этом случае «внутренности» интерфейса не подменяются, дефолтный метод выполняется с неизменным статическим методом printed. А использование подобной конструкции даже не дало бы возможности скомпилировать код:
@Override
static void printed(String s) {
System.out.println("printing from class ::"+s);
}
Таким образом, очевидно, что «неизменность» статических методов в интерфейсе удобна для поддержания целостности кода дефолтных методом. Потому что наряду с приватными дефолтными методами и статические методы также могут использоваться в дефолтных методах для «расшивки» и структурной организации кода.
Впрочем, невозможность переопределения статических методов предусмотрена изначально и не является исключительной возможностью статических методов в интерфейсах. Поскольку статические методы не являются частью состояния объекта, как, скажем, переменные экземпляра класса.
Отсюда вытекает одно из основных различий между дефолтными и статическими методами: дефолтные методы предназначены для имплементации в классах, а статические не предусматривают подобное.
Кроме рассмотренных выше способов использования статических классов в интерфейсах
существует также множество прочих способов оригинального и эффективного использования статических методов в интерфейсах. Например, использование функционального интерфейса и статических методов, возвращающих нам типы объектов интерфейса с уже реализованным функционалом:
@FunctionalInterface
interface Printer {
void print(String text);
static Printer A() {
return text -> System.out.println("Printer A: " + text);
}
static Printer B() {
return text -> System.out.println("Printer A: " + text);
}
static Printer C() {
return text -> System.out.println("Printer C: " + text);
}
}
Функциональный интерфейс позволяет нам эффективно использовать лямбда-выражения, а статические методы обладают тем же функционалом, что и внутренние статические классы, вложенные в этот интерфейс, при этом имплементирующие этот же интерфейс и реализующие, например, встроенные возможности заглушек или прочий функционал, представляя возможность создавать объекты типа данного интерфейса.
Запустим код:
public class PrinterTestDrive {
public static void main(String[] args) {
Printer.A().print("text");
Printer.B().print("text");
Printer.C().print("text");
}
}
Результат:
"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" -Didea.launcher.port=54890 "-
Printer A: text
Printer A: text
Printer C: text
Process finished with exit code 0