Как известно, начиная с версии JDK 8.0 в Java наряду с так называемыми дефолтными методами появились также и статические методы. Например, до появления Java 8 нельзя было прописывать подобный интерфейс:
public interface IStaticMetodContainer {
static void printed(String s) {
System.out.println("printing::"+s);
}
}
Тем не менее, была возможность использовать статический вложенный класс в интерфейсе (начиная с версии Java 2.0). Используя возможности только Java 2.0 этот же пример выше мог бы выглядеть, например, следующим образом:
public interface IClassContainer {
class StaticNestedClass{
public static void printed(String s) {
System.out.println("printing::"+s);
}
}
}
Создадим специальный класс IClassTest для проверки работы методов. И запустим метод main:
public class IClassTest {
public static void main(String[] args) {
IStaticMetodContainer.printed("test");
IClassContainer.StaticNestedClass.printed("test");
}
}
Как видим, результат идентичен для обоих вариантов:
"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" -Didea.launcher.port=54478 "-
printing::test
printing::test
Process finished with exit code 0
Таким образом, немедленно напрашивается первый вывод об особенностях применения статических методов в интерфейсах, а именно, что они могут в некоторых случаях заменить собой использование статических классов в интерфейсах, несколько упростив логику инкапсулирования кода для ряда задач. И, действительно, статические методов довольно часто используются в качестве вспомогательных или утилитных методов. Что, собственно, присуще и статическим классам в интерфейсах.
Еще одной интересной особенностью статических методов в интерфейсах является невозможность переопределения подобного метода в классе, имплементирующем интерфейс. Статические методы являются частью интерфейса и не «передаются» классу, поэтому можно сказать, что переопределение в данном случае не то, что невозможно, но и непредусмотрено. Поэтому, можно в классе-имплементоре спокойно реализовывать свой метод с идентичной сигнатурой, однако, он все равно не заменит аналогичный метод в интерфейсе и не будет сообщений от IDE с требованием вставить аннотацию @Override. Более того, использование аннотации @Override даст ошибку компиляции. Рассмотрим на следующем примере, предварительно немного видоизменив исходный интерфейс IStaticMetodContainer и добавив в него дефолтный метод:
public interface IStaticMetodContainer {
static void printed(String s) {
System.out.println("printing::"+s);
}
default void print(String s) {
printed("default part included "+s);
}
}
И определим следующий класс-имплементор для данного интерфейса:
public class IStaticMetodContainerImpl implements IStaticMetodContainer {
static void printed(String s) {
System.out.println("printing from class ::"+s);
}