В подклассе из другого пакета почему защищённый экземплярный метод базового класса нельзя вызвать через произвольную ссылку на базовый тип?
В другом пакете protected-метод доступен подклассу только через объект самого подкласса или его потомка, а не через произвольную ссылку на базовый тип. Это ограничение проверяется на этапе компиляции и защищает наследуемый контракт от использования как общего публичного API.
Если вызов разрешён, дальнейшее поведение остаётся полиморфным: фактическая реализация переопределённого метода выбирается по типу объекта во время выполнения.
Модификатор protected решает компромисс между полной закрытостью метода и публичным доступом. Он позволяет базовому классу предоставлять точки расширения своим наследникам, не открывая их всем клиентам класса.
Границы пакетов дополнительно разделяют внутреннее сотрудничество классов и наследование. Внутри того же пакета защищённый член доступен по обычным правилам доступа пакета, но за пределами пакета наследник получает более узкий сценарий доступа.
Представим библиотечный базовый класс в одном пакете и пользовательский подкласс в другом. Если разрешить такому подклассу обращаться к защищённому методу через любую ссылку на базовый класс, наследник фактически получил бы возможность использовать этот метод на объектах, которые не относятся к его ветви наследования.
Это может нарушить инкапсуляцию и создать ошибочное ожидание, что protected-метод является почти публичным. Важно также не путать две проверки: доступность метода компилятором и выбор переопределённой реализации JVM — это разные этапы.
Для подкласса в другом пакете допустимы вызовы защищённого экземплярного метода через this, super, ссылку на сам подкласс или ссылку на его производный тип. Ссылка, статически типизированная непосредственно базовым классом, для такого вызова недопустима.
Метод forbidden не компилируется: вызывающий объект имеет тип Base, а код находится в подклассе из другого пакета. Вызов через Child разрешён, потому что выражение явно относится к текущей иерархии наследования.
Это именно правило доступа, а не механизм выбора метода. Например, если Child переопределит audit, разрешённый вызов через ссылку Child будет динамически направлен в реализацию Child; но сначала компилятор должен установить, что сам вызов допустим.
Внутри одного пакета ограничение слабее: защищённый член доступен другим классам этого пакета через ссылку на базовый тип. Поэтому перенос класса через границу пакета может изменить компилируемость уже существующего обращения.
Практический компромисс таков: protected удобен для контролируемого расширения, но увеличивает связанность базового класса с наследниками. Если метод не является частью осознанного контракта расширения, лучше рассмотреть композицию, пакетную видимость или публичный метод более высокого уровня.
Библиотека содержит базовый класс обработчика в пакете framework, а приложение расширяет его в пакете application. Базовый класс предоставляет защищённый метод подготовки контекста, который должен вызываться из шаблонного алгоритма наследника.
Рассматривались три варианта. Сделать метод public проще для использования, но это раскрывает внутренний механизм всем клиентам и позволяет вызывать его на неподготовленном объекте. Оставить метод пакетным безопаснее, но внешний наследник не сможет его использовать. Передать подготовку через композицию лучше изолирует детали, однако требует отдельного объекта и изменения архитектуры.
Выбран protected-метод с вызовом из контролируемого шаблонного метода базового класса. Это сохранило возможность расширения в другом пакете и не превратило внутренний шаг обработки в публичный API. Дополнительно контракт метода зафиксировали документацией, потому что защищённые методы всё равно становятся зависимостью для внешних наследников.
Нет. В пределах того же пакета защищённый метод доступен не только наследникам, но и другим классам пакета по обычным правилам пакетной видимости. Особое ограничение на квалификатор вызова возникает для наследника, находящегося в другом пакете.
Поэтому нельзя формулировать правило как «protected всегда вызывается только через объект наследника». Точная формулировка зависит от того, находится ли обращающийся код в том же пакете, что и объявивший класс.
Нет. Доступ и диспетчеризация — независимые свойства. После успешной проверки доступа вызов переопределяемого экземплярного метода обычно выбирает реализацию по фактическому классу объекта.
Вопрос о protected может остановить программу ещё на компиляции, но он не превращает разрешённый вызов в статический. Статический выбор характерен для статических методов, перегрузок и некоторых других конструкций, а не для обычного переопределения экземплярного метода.
Потому что статический тип ссылки уже подтверждает принадлежность объекта к ветви наследования, расширяемой текущим подклассом. Объект более производного класса также является экземпляром этого подкласса, поэтому такое обращение сохраняет установленную границу доступа.
При этом статический тип всё равно важен: если тот же объект помещён в ссылку на базовый класс, проверка доступа использует эту форму выражения и может отклонить вызов. Изменение только типа ссылки способно изменить результат компиляции, не меняя сам объект.