Стоит сразу сказать, это очень плохая практика. Такое изменение грубо нарушает принципы сокрытия данных, и потенциально ломает инвариантность состояния объекта.
Для этого трюка необходимо прибегнуть к использованию
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);