Предполагая, что нет 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";
}
}
если ты не владелец класса ... я тебя чувствую!
Для более подробной информации о том, почему это поведение читать это ?