Предполагая, что нет SecurityManager
мешает вам сделать это, вы можете использовать, setAccessible
чтобы обойти private
и сбросить модификатор, чтобы избавиться от него final
, и фактически изменить private static final
поле.
Вот пример:
import java.lang.reflect.*;
public class EverythingIsTrue {
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
public static void main(String args[]) throws Exception {
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
}
}
Предполагая, что нет SecurityException
, вышеприведенный код печатает"Everything is true"
.
То, что на самом деле сделано здесь, выглядит следующим образом:
- Примитивные
boolean
значения true
и false
в main
автоматически помещаются в ссылочный тип Boolean
«константы» Boolean.TRUE
иBoolean.FALSE
- Отражение используется для изменения,
public static final Boolean.FALSE
чтобы ссылаться на Boolean
упомянутыйBoolean.TRUE
- В результате, впоследствии, когда a
false
автоматически помещается в ящик Boolean.FALSE
, он ссылается на тот, Boolean
на который ссылаетсяBoolean.TRUE
- Все, что было
"false"
сейчас,"true"
Смежные вопросы
Предостережения
Необходимо проявлять крайнюю осторожность, когда вы делаете что-то подобное. Он может не работать, потому что SecurityManager
может присутствовать, но даже если это не так, в зависимости от модели использования, он может работать или не работать.
JLS 17.5.3 Последующая модификация конечных полей
В некоторых случаях, таких как десериализация, система должна будет изменить final
поля объекта после построения. final
поля могут быть изменены с помощью отражения и других зависящих от реализации средств. Единственный шаблон, в котором это имеет разумную семантику, это шаблон, в котором объект создается, а затем final
поля объекта обновляются. Объект не должен быть видимым для других потоков, а также final
поля не должны быть прочитаны, пока не final
будут завершены все обновления полей объекта. Замораживание final
поля происходит как в конце конструктора, в котором final
оно установлено, так и сразу после каждой модификации final
поля с помощью отражения или другого специального механизма.
Даже тогда, есть ряд осложнений. Если final
поле инициализируется константой времени компиляции в объявлении поля, изменения в этом final
поле могут не наблюдаться, так как использование этого final
поля заменяется во время компиляции константой времени компиляции.
Другая проблема заключается в том, что спецификация допускает агрессивную оптимизацию final
полей. Внутри потока допустимо переупорядочивать операции чтения final
поля с теми модификациями конечного поля, которые не имеют места в конструкторе.
Смотрите также
- JLS 15.28 Константа Выражение
- Маловероятно, что этот метод работает с примитивом
private static final boolean
, потому что он встроен как константа времени компиляции и, таким образом, «новое» значение может быть не наблюдаемым
Приложение: О побитовой манипуляции
По существу,
field.getModifiers() & ~Modifier.FINAL
выключает бит, соответствующий Modifier.FINAL
с field.getModifiers()
. &
является побитовым и~
является побитовым дополнением.
Смотрите также
Помните постоянные выражения
Все еще не в состоянии решить это?, Впал в депрессию, как я сделал для этого? Ваш код выглядит так?
public class A {
private final String myVar = "Some Value";
}
Прочитав комментарии к этому ответу, особенно @Pshemo, он напомнил мне, что выражения констант обрабатываются по-разному, поэтому изменить их будет невозможно . Следовательно, вам нужно будет изменить свой код, чтобы он выглядел так:
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
если ты не владелец класса ... я тебя чувствую!
Для более подробной информации о том, почему это поведение читать это ?