Какой механизм объясняет, почему статический метод интерфейса нельзя вызвать через переменную типа реализующего класса?
Статический метод интерфейса принадлежит самому интерфейсу, а не его экземплярам и не классам-реализациям. Поэтому его вызывают через имя интерфейса; через переменную типа интерфейса или реализующего класса такой вызов не компилируется.
До появления default-методов и статических методов в интерфейсах Java 8 интерфейсы в основном описывали экземплярный контракт: какие методы должен поддерживать объект. Позднее статические методы позволили размещать связанные с контрактом вспомогательные операции непосредственно в интерфейсе, не создавая отдельный класс-утилиту.
При этом статический метод не стал частью полиморфного поведения объекта. Такое ограничение сохраняет чёткое различие между методами экземпляра и методами типа.
Ошибочное ожидание возникает, когда переменная имеет тип интерфейса, а объект фактически создан классом-реализацией. Раз экземпляр поддерживает интерфейс, может показаться логичным вызвать через него любой метод интерфейса.
Если перепутать статический и экземплярный вызов, программа не скомпилируется. Кроме того, попытка сделать такой метод переопределяемым противоречила бы его природе: выбор статического метода не зависит от фактического класса объекта.
Статический метод разрешается на этапе компиляции по имени типа. Для интерфейса этим типом должно быть имя самого интерфейса. Метод не наследуется классами-реализациями, не участвует в динамическом связывании и не может быть переопределён.
Переменная service содержит ссылку на объект, но статический метод не использует этот объект как получатель. Поэтому корректная форма вызова — Service.version().
Класс-реализация может объявить собственный статический метод с таким же именем, но это не будет переопределением метода интерфейса. Это два независимых метода, каждый вызывается через имя своего типа.
Команда размещает в интерфейсе Parser статический метод проверки входных данных. Разработчик пытается вызывать его через объект конкретного парсера, рассчитывая на единый полиморфный API.
Вариант с вызовом через объект не компилируется и концептуально неверен: проверка не зависит от состояния экземпляра. Вариант с default-методом технически создаёт экземплярный контракт, но заставляет реализации наследовать поведение и может создавать конфликты с другими default-методами.
Отдельный класс-утилита подходит для общей логики, не связанной с интерфейсом, но разносит связанные понятия по разным типам. В данном случае выбран статический метод интерфейса и вызов через имя Parser: это явно показывает отсутствие зависимости от конкретной реализации и не создаёт лишнего экземплярного контракта.
Нет. Статические методы интерфейса не наследуются классом и не участвуют в виртуальном вызове. Класс может объявить одноимённый статический метод, но он будет самостоятельным методом, а не переопределением.
Конфликта реализации, как у одноимённых default-методов, не возникает: статические методы интерфейсов не наследуются и не образуют экземплярный контракт. Каждый метод вызывается с квалификацией соответствующего интерфейса.
Потому что статический вызов разрешается по объявленному типу и не использует динамический тип объекта. Даже если переменная интерфейсного типа ссылается на разные реализации, обращение к статическому методу интерфейса всегда означает вызов метода, объявленного именно в этом интерфейсе.