Для этого трюка необходимо прибегнуть к использованию 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);