Класс объявляет реализацию интерфейса, но сам не содержит его метода: когда вызов через интерфейсную ссылку всё же будет корректен?
Вызов будет корректен, если класс наследует от суперкласса подходящую public экземплярную реализацию метода интерфейса. Суперкласс не обязан сам объявлять реализацию этого интерфейса: достаточно, чтобы унаследованный метод соответствовал его контракту.
Если унаследованный метод недоступен, является несовместимым по сигнатуре или класс остаётся конкретным при наличии нереализованного абстрактного метода, компиляция завершится ошибкой.
Интерфейсы отделяют контракт типа от конкретной иерархии реализации. Поэтому Java допускает, чтобы класс получил реализацию метода от суперкласса, а совместимость с интерфейсом объявил только в подклассе.
Такой подход позволяет добавлять интерфейс к существующей иерархии без дублирования уже написанной реализации. Иначе каждому подклассу пришлось бы повторно объявлять методы, которые фактически уже доступны через наследование.
Представим базовый класс с публичным методом и подкласс, который объявляет реализацию интерфейса с методом такой же сигнатуры. Возникает вопрос: должен ли подкласс обязательно переопределить метод, или унаследованной реализации достаточно.
Неверное предположение может привести либо к лишнему дублированию кода, либо к ошибке компиляции из-за попытки использовать метод с неподходящей видимостью. Особенно важно отличать public-метод от private-метода: private-метод не наследуется и не может реализовать метод интерфейса.
Компилятор рассматривает унаследованные методы при проверке того, реализованы ли методы интерфейса. Если конкретный класс объявляет implements и получает от суперкласса public экземплярный метод с совместимой сигнатурой, этот метод считается реализацией интерфейсного контракта.
Суперкласс при этом может вообще не упоминать интерфейс. Связь с интерфейсом устанавливается в подклассе, а реализация берётся из уже существующей цепочки наследования.
Вызов разрешается через интерфейсную ссылку, но фактическая реализация найдена в классе Base и унаследована Report. Если Report переопределит print, при вызове будет выбрана уже переопределённая реализация благодаря динамическому полиморфизму.
Метод должен быть доступен как реализация интерфейсного метода: обычно это означает public, нестатический и совместимый по параметрам и возвращаемому типу. Private-метод суперкласса не наследуется, поэтому совпадение имени и параметров само по себе ничего не даёт.
Если суперкласс объявляет метод абстрактным, конкретный подкласс обязан предоставить реализацию самостоятельно. Абстрактный подкласс может отложить эту обязанность дальше по иерархии.
В существующей системе есть базовый класс AuditedEntity с public-методом получения идентификатора. Новый класс должен реализовать интерфейс Identifiable, содержащий метод с тем же контрактом.
Вариант с копированием метода в новом классе формально работает, но создаёт дублирование и риск расхождения поведения. Вариант с изменением метода базового класса на private не подходит: такой метод перестанет наследоваться и больше не сможет служить реализацией интерфейса.
Выбранное решение — оставить совместимый public-метод в базовом классе и объявить интерфейс в новом классе. Это сохраняет единственную реализацию, уменьшает объём кода и позволяет использовать объект через ссылку типа Identifiable.
Решение не следует применять, если метод базового класса случайно совпадает с интерфейсом только по имени, но имеет другую сигнатуру или неподходящую видимость. В таком случае нужно явно реализовать метод в подклассе либо изменить контракт осознанно.
Нет. Подкласс может впервые объявить implements, а совместимый public-метод получить от суперкласса. Компилятор проверяет наличие подходящей реализации в итоговом типе, а не обязательное наличие implements у каждого класса в цепочке.
Нет. Private-методы не наследуются и доступны только внутри класса, где объявлены. Поэтому одинаковые имя и параметры не превращают private-метод в реализацию интерфейсного контракта; конкретному подклассу потребуется собственный public-метод.
Вызов через интерфейсную ссылку будет использовать переопределение подкласса, если оно корректно переопределяет метод. Интерфейсная ссылка ограничивает доступный контракт, но не отменяет динамический выбор реализации по фактическому объекту; поэтому новая реализация подкласса будет выбрана во время выполнения.