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