Карта / ООП / Рефлексия

Рефлексия

Рефлексия — возможность изучать и изменять структуру программы в рантайме. Обычно код работает с типами, известными на этапе компиляции. Рефлексия позволяет получить список методов класса, создать объект по имени класса-строке, вызвать метод не зная его имени заранее.

Class<?> clazz = Class.forName("com.app.model.User"); // загрузить класс по имени

// Получить информацию о классе
Method[] methods = clazz.getMethods();          // все публичные методы
Field[]  fields  = clazz.getDeclaredFields();   // все поля (включая private)

// Создать объект
Object user = clazz.getDeclaredConstructor().newInstance();

// Вызвать метод
Method getName = clazz.getMethod("getName");
String name = (String) getName.invoke(user);

// Доступ к private полю
Field field = clazz.getDeclaredField("password");
field.setAccessible(true);   // снять ограничение доступа
String pwd = (String) field.get(user);

Где это реально используется: Spring IoC (сканирует классы, создаёт бины), JPA (маппинг полей на колонки), JUnit (находит методы с @Test), Jackson (сериализует/десериализует поля).

Копнуть глубже

Почему рефлексия медленная. Обычный вызов метода — JVM знает тип и метод на этапе компиляции, JIT оптимизирует, иногда инлайнит. Рефлексивный вызов: JVM каждый раз ищет метод по имени, проверяет права доступа, не может инлайнить. Разница — в 3–10 раз медленнее для одного вызова. Фреймворки решают это кэшированием: Spring ищет методы один раз при старте, кэширует Method-объекты и переиспользует.

setAccessible(true) — обход инкапсуляции. В Java 9+ добавлены ограничения через модульную систему (JPMS). setAccessible может кинуть InaccessibleObjectException если модуль не открыт явно. Именно поэтому Spring/Hibernate требуют --add-opens JVM-флаги при работе с Java 17+.

Рефлексия и Generics — стирание типов. Из-за type erasure List<String> и List<Integer> в рантайме неотличимы через рефлексию. Но есть способ получить generic-тип через ParameterizedType:

// Поле типа List<String>
Field f = MyClass.class.getDeclaredField("names"); // List<String>
ParameterizedType pt = (ParameterizedType) f.getGenericType();
Type typeArg = pt.getActualTypeArguments()[0]; // class java.lang.String

Jackson использует TypeReference именно для этого — чтобы десериализовать в List<User>, а не List<Object>.

🎤 Закрыл тему, если можешь объяснить:
• что такое рефлексия и где она используется в реальном коде;
• почему рефлексия медленная и как фреймворки её ускоряют (если дошёл до 2-го слоя).