Как скрывать поля и методы в Java
Что проверяют
За простой формулировкой прячутся две темы, и сильный кандидат называет обе: инкапсуляция через модификаторы доступа и сокрытие (hiding) членов класса при наследовании. Следом обычно просят объяснить, чем сокрытие статического метода отличается от переопределения.
Как отвечать
Модификаторы доступа от строгого к открытому:
private: виден только внутри класса верхнего уровня, включая вложенные классы;- package-private (без модификатора): виден в пределах пакета;
protected: пакет плюс наследники в других пакетах. Частая ошибка думать, что это «только наследники»;public: виден всем, кому доступен сам класс.
Поверх этого с Java 9 работает модульная система: public класс из пакета, который не перечислен в exports файла module-info.java, снаружи модуля недоступен. Рефлексия с setAccessible(true) в пакеты модуля без opens тоже не проходит. Наследование ограничивают sealed классы из Java 17.
Вторая тема, сокрытие в строгом смысле:
- поле с тем же именем в наследнике: скрывает поле родителя. Поля не полиморфны, при
Parent p = new Child()выражениеp.nameвернёт полеParent; - статический метод с той же сигнатурой: скрывает, а не переопределяет. Вызов выбирается по объявленному типу на этапе компиляции, и
@Overrideна нём даст ошибку; - экземплярный метод: переопределяется и вызывается по реальному типу объекта;
privateметод: не наследуется, одноимённый метод в наследнике просто новый метод.
Где спотыкаются
Делают все поля private и тут же генерируют геттер и сеттер на каждое. Формально инкапсуляция есть, по сути класс открыт целиком.
Возвращают из геттера внутренний изменяемый List, и вызывающий код меняет состояние в обход класса. Отдавайте List.copyOf или Collections.unmodifiableList.
Путают сокрытие с переопределением и уверенно говорят, что статический метод вызовется по реальному типу объекта.