Якщо ні, що 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";
}
}
якщо ти не власник класу ... я тебе відчуваю!
Детальніше про те, чому ця поведінка читає це ?