В чём состоит ограничение private-методов интерфейса для класса, который этот интерфейс реализует?
Private-метод интерфейса не наследуется классом-реализатором, недоступен ему и не может быть переопределён. Он существует только для внутреннего использования методами самого интерфейса, например его default-методами.
Класс может объявить метод с такой же сигнатурой, но это будет независимый метод: он не переопределяет private-метод интерфейса и не участвует в его вызове.
В Java 8 появились default-методы, чтобы интерфейсы могли содержать готовую реализацию и развиваться без обязательного изменения всех классов-реализаторов. Однако несколько default-методов внутри одного интерфейса могли повторять общую вспомогательную логику.
В Java 9 появились private-методы интерфейсов. Они решили проблему повторения кода между default- и static-методами, сохранив вспомогательную реализацию скрытой от классов-реализаторов.
Интерфейс может иметь несколько публичных методов с общей внутренней частью. Если сделать вспомогательный метод публичным или default, он станет частью внешнего контракта и создаст дополнительную обязанность для пользователей интерфейса.
Если разработчик ошибочно считает private-метод интерфейса унаследованным, он может ожидать, что класс переопределит эту логику. На практике реализация интерфейса не получит доступа к такому методу, а одноимённый метод класса не изменит поведение default-метода интерфейса.
Private-метод интерфейса является членом самого интерфейса, но не входит в набор наследуемых членов класса. Обращаться к нему могут только разрешённые методы, объявленные внутри этого интерфейса; внешний класс не может вызвать его через экземпляр или через имя интерфейса.
При вызове private-метода из default-метода используется конкретная реализация, принадлежащая объявившему её интерфейсу. Вызов не является обычным полиморфным вызовом, поэтому одноимённый метод в классе-реализаторе не перехватывает его.
В этом примере Order.normalize не переопределяет Auditable.normalize: private-метод интерфейса не наследуется. Поэтому audit использует внутренний normalize интерфейса и возвращает нормализованную строку без префикса class:.
Такой механизм полезен для инкапсуляции общей логики интерфейса. Ограничение состоит в том, что эту логику нельзя заменить в классе через переопределение; если нужна кастомизация, её следует выразить публичным или default-методом контракта либо передать через другой проектный механизм.
Команда поддерживает интерфейс форматирования документов с несколькими default-методами. Каждый из них должен одинаково очищать пробелы и нормализовать регистр, но эта логика не должна становиться частью API.
Первый вариант — сделать вспомогательный метод публичным. Он прост для повторного использования, но расширяет контракт и позволяет клиентам зависеть от детали реализации. Второй вариант — продублировать нормализацию в каждом default-методе; это не расширяет API, но создаёт риск расхождения реализаций.
Выбран private-метод интерфейса. Он устраняет дублирование и скрывает деталь реализации, а классы-реализаторы не могут случайно подменить алгоритм. Если отдельному классу потребуется другой алгоритм, контракт следует изменить явно, а не рассчитывать на одноимённый метод в классе.
Нет. Такой метод не входит в доступный внешний контракт интерфейса. Ссылка на интерфейс позволяет обращаться только к его доступным методам, но не к private-членам.
Это ограничение действует даже тогда, когда объект фактически является экземпляром класса-реализатора. Динамический тип объекта не расширяет права доступа к private-методу интерфейса.
Нет. Переопределение возможно только для метода, который наследуется и доступен как часть соответствующего контракта. Private-метод интерфейса классом не наследуется, поэтому метод класса с той же сигнатурой является самостоятельным.
Следствие важно при разрешении вызова: default-метод интерфейса обращается к своей private-реализации, а не к методу класса с совпадающим именем.
Нет. Они не видны через тип интерфейса и не участвуют в переопределении, выборе реализации по динамическому типу или разрешении конфликтов default-методов.
Их назначение — структурировать реализацию самого интерфейса. Для полиморфного поведения метод должен быть доступным членом контракта, например абстрактным или default-методом, но тогда он уже становится частью API и должен проектироваться с учётом классов-реализаторов.