Keine Angenommen SecurityManager
wird Sie tun dies zu verhindern, können Sie setAccessible
erhalten um private
den Modifikator und Zurücksetzen , um loszuwerden final
, und tatsächlich ein ändern private static final
Feld.
Hier ist ein Beispiel:
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"
}
}
Angenommen, nein SecurityException
wird geworfen, wird der obige Code gedruckt "Everything is true"
.
Was hier tatsächlich gemacht wird, ist wie folgt:
- Die primitiven
boolean
Werte true
und false
in main
werden automatisch an den Referenztyp Boolean
"Konstanten" Boolean.TRUE
und " referenziert "Boolean.FALSE
- Reflexion wird verwendet, um das zu ändern
public static final Boolean.FALSE
, um auf das Boolean
Bezug zu nehmen, auf das verwiesen wirdBoolean.TRUE
- Infolgedessen bezieht sich a, wann immer ein
false
Autobox gesendet wird Boolean.FALSE
, auf dasselbe Boolean
wie das, auf das von verwiesen wirdBoolean.TRUE
- Alles was
"false"
jetzt war ist"true"
Verwandte Fragen
Vorsichtsmaßnahmen
Wenn Sie so etwas tun, sollten Sie äußerst vorsichtig sein. Es funktioniert möglicherweise nicht, weil a SecurityManager
vorhanden sein kann, aber selbst wenn dies nicht der Fall ist, kann es je nach Verwendungsmuster funktionieren oder auch nicht.
JLS 17.5.3 Nachträgliche Änderung der endgültigen Felder
In einigen Fällen, z. B. bei der Deserialisierung, muss das System die final
Felder eines Objekts nach der Erstellung ändern . final
Felder können durch Reflexion und andere implementierungsabhängige Mittel geändert werden. Das einzige Muster, in dem dies eine vernünftige Semantik hat, ist eines, in dem ein Objekt konstruiert wird und dann die final
Felder des Objekts aktualisiert werden. Das Objekt sollte weder für andere Threads sichtbar gemacht noch die final
Felder gelesen werden, bis alle Aktualisierungen der final
Felder des Objekts abgeschlossen sind. Einfrieren eines final
Feldes tritt sowohl am Ende des Konstruktors, in dem das final
Feld eingestellt ist, als auch unmittelbar nach jeder Änderung eines final
Feldes durch Reflexion oder einen anderen speziellen Mechanismus auf.
Selbst dann gibt es eine Reihe von Komplikationen. Wenn ein final
Feld in der Felddeklaration mit einer Kompilierungszeitkonstante initialisiert wird, werden Änderungen am final
Feld möglicherweise nicht beobachtet, da die Verwendung dieses final
Felds zur Kompilierungszeit durch die Kompilierungszeitkonstante ersetzt wird.
Ein weiteres Problem besteht darin, dass die Spezifikation eine aggressive Optimierung von final
Feldern ermöglicht. Innerhalb eines Threads ist es zulässig, Lesevorgänge eines final
Feldes mit den Änderungen eines endgültigen Felds neu anzuordnen , die nicht im Konstruktor stattfinden.
Siehe auch
- JLS 15.28 Konstante Expression
- Es ist unwahrscheinlich, dass diese Technik mit einem
private static final boolean
Grundelement funktioniert , da sie als Konstante für die Kompilierungszeit inlinierbar ist und daher der "neue" Wert möglicherweise nicht beobachtbar ist
Anhang: Zur bitweisen Manipulation
Im Wesentlichen,
field.getModifiers() & ~Modifier.FINAL
schaltet das Bit aus von Modifier.FINAL
aus field.getModifiers()
. &
ist das bitweise und und ~
ist das bitweise Komplement.
Siehe auch
Denken Sie an konstante Ausdrücke
Immer noch nicht in der Lage, dies zu lösen? Sind Sie auf Depressionen gefallen, wie ich es dafür getan habe? Sieht Ihr Code so aus?
public class A {
private final String myVar = "Some Value";
}
Beim Lesen der Kommentare zu dieser Antwort, insbesondere der von @Pshemo, wurde ich daran erinnert, dass konstante Ausdrücke unterschiedlich behandelt werden, sodass es unmöglich ist , sie zu ändern. Daher müssen Sie Ihren Code so ändern, dass er so aussieht:
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
wenn du nicht der Besitzer der Klasse bist ... ich fühle dich!
Für weitere Details darüber, warum dieses Verhalten dies liest ?