Динамический доступ через Reflection

Базовый Java
≈ 2 мин чтения

Когда член выбирается во время выполнения

Reflection умеет не только описывать структуру типа. Объекты Field, Method и Constructor могут использоваться для динамического доступа. Это нужно, например, инфраструктурному коду, который получает имя метода из конфигурации или создаёт экземпляр класса, выбранного только во время запуска.

Вызов метода через Method

class Greeter {
    public String greet(String name) {
        return "Hello, " + name;
    }
}

Greeter greeter = new Greeter();
Method method = Greeter.class.getMethod("greet", String.class);
Object result = method.invoke(greeter, "Ann");

Первый аргумент invoke() — объект, на котором вызывается экземплярный метод, а остальные значения передаются как его аргументы. Возвращаемое значение имеет тип Object, потому что Reflection заранее не знает конкретный тип результата в месте вызова.

Создание объекта через Constructor

Constructor<StringBuilder> constructor =
        StringBuilder.class.getConstructor(int.class);

StringBuilder builder = constructor.newInstance(64);

Вместо прямого new сначала выбирается описание конструктора, а затем newInstance() создаёт объект с переданными аргументами.

Чтение и изменение поля

class Counter {
    public int value = 10;
}

Counter counter = new Counter();
Field field = Counter.class.getField("value");

int oldValue = (int) field.get(counter);
field.set(counter, 20);

У статического поля объект-получатель не нужен, а для поля экземпляра нужно передать конкретный объект. Reflection проверяет совместимость типов во время выполнения, поэтому многие ошибки, которые при прямом обращении поймал бы компилятор, здесь проявляются позже.

Непубличные члены и доступность

Для непубличного члена одного getDeclared... недостаточно. Reflection всё равно учитывает правила доступа. trySetAccessible() может попытаться разрешить доступ и вернуть false, если это невозможно. В модульном приложении границы модулей и открытых пакетов также ограничивают такой доступ.

Не делай обход инкапсуляции обычной техникой приложения. Динамический доступ оправдан в инфраструктурном коде, библиотеках и фреймворках, но бизнес-код обычно проще и надёжнее строить на обычных методах и типах.