Для этого трюка необходимо прибегнуть к использованию Reflection API.
Сначала получим дескриптор поля – экземпляр класса
Field
. У объекта метакласса Class<X>
интересующего нас класса вызовем метод getDeclaredField()
. Просто getField()
не сработает, потому что он работает только с публичными полями. Параметром передается строка с именем поля.Полученного экземпляра
Field
уже достаточно для доступа к изменяемым приватным полям. Перед обращением требуется сделать его доступным, вызвав setAccessible(true)
.Сам доступ осуществляется методами
get*()
и set*()
. Так как Field
представляет дескриптор поля класса, без привязки к конкретному экземпляру класса, экземпляр передается параметром в методы доступа. Для статического поля передается null
.Чтобы побороть неизменяемость финального поля, нужно снять его модификатор
final
. Все модификаторы поля хранятся в поле modifiers
дескриптора. То есть, нужно также с помощью рефлекшена сделать доступным и обновить поле уже объекта Field
.Поле
modifiers
хранит модификаторы в виде битовой маски. Для изменения придется прибегнуть к битовым операторам.Полный код установки значения 42 в поле
myField
объекта myObject
выглядит так:Field field = myObject.class.getDeclaredField( "myField" );
field.setAccessible( true );
Field modifiersField = Field.class.getDeclaredField( "modifiers" );
modifiersField.setAccessible( true );
modifiersField.setInt( field, field.getModifiers() & ~Modifier.FINAL );
field.setInt(myObject, 42);