Ограничения и особенности рефлексии
Гибкость покупается ценой проверок компилятора
При обычном вызове service.save(user) компилятор знает тип объекта,
наличие метода и типы аргументов. В рефлексивном коде имя метода может быть строкой,
а аргументы передаются динамически. Ошибку в имени или несовместимый тип программа часто обнаружит только во время выполнения.
Method method = UserService.class.getMethod("save", User.class);
method.invoke(service, user);
Такой код полезен, если имя действительно должно быть динамическим. Если же метод заранее известен, Reflection лишь убирает часть полезных проверок и делает код сложнее для чтения и рефакторинга.
Инкапсуляция и модули остаются реальными границами
Наличие setAccessible(true) не означает, что любой private-член всегда можно открыть.
Современная Java учитывает границы модулей: если пакет не открыт вызывающему модулю,
попытка подавить проверку доступа может завершиться InaccessibleObjectException.
Метод trySetAccessible() позволяет проверить возможность мягче — через результат boolean.
Generics не становятся полностью доступными во время выполнения
Reflection может читать сохранённую generic-информацию объявлений через специальные методы API,
но стирание типов никуда не исчезает. Например, во время выполнения обычные объекты
List<String> и List<Integer> имеют один runtime-класс List.
Нельзя рассчитывать, что Reflection восстановит тип каждого generic-значения из объекта.
Runtime-аннотации нужно сохранять явно
Если фреймворк ищет пользовательскую аннотацию через Reflection, у неё должна быть
@Retention(RetentionPolicy.RUNTIME). Аннотация с политикой SOURCE
или обычной политикой CLASS для такого сценария не подходит.
Производительность и читаемость
Не стоит считать каждый рефлексивный вызов катастрофически медленным: JVM и библиотека Reflection давно оптимизируются.
Но динамический поиск членов, проверки доступа, упаковка аргументов и отсутствие обычной статической связи всё равно имеют цену.
В горячем участке кода найденные Method или Field обычно не ищут заново на каждой операции.
Главная практическая цена Reflection часто даже не скорость, а сложность сопровождения: строковые имена хуже переживают переименование, ошибки проявляются позже, а поток выполнения сложнее проследить глазами.