Keine Angenommen SecurityManagerwird Sie tun dies zu verhindern, können Sie setAccessibleerhalten um privateden Modifikator und Zurücksetzen , um loszuwerden final, und tatsächlich ein ändern private static finalFeld.
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 SecurityExceptionwird geworfen, wird der obige Code gedruckt "Everything is true".
Was hier tatsächlich gemacht wird, ist wie folgt:
- Die primitiven
booleanWerte trueund falsein mainwerden automatisch an den Referenztyp Boolean"Konstanten" Boolean.TRUEund " referenziert "Boolean.FALSE
- Reflexion wird verwendet, um das zu ändern
public static final Boolean.FALSE, um auf das BooleanBezug zu nehmen, auf das verwiesen wirdBoolean.TRUE
- Infolgedessen bezieht sich a, wann immer ein
falseAutobox gesendet wird Boolean.FALSE, auf dasselbe Booleanwie 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 SecurityManagervorhanden 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 finalFelder eines Objekts nach der Erstellung ändern . finalFelder 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 finalFelder des Objekts aktualisiert werden. Das Objekt sollte weder für andere Threads sichtbar gemacht noch die finalFelder gelesen werden, bis alle Aktualisierungen der finalFelder des Objekts abgeschlossen sind. Einfrieren eines finalFeldes tritt sowohl am Ende des Konstruktors, in dem das finalFeld eingestellt ist, als auch unmittelbar nach jeder Änderung eines finalFeldes durch Reflexion oder einen anderen speziellen Mechanismus auf.
Selbst dann gibt es eine Reihe von Komplikationen. Wenn ein finalFeld in der Felddeklaration mit einer Kompilierungszeitkonstante initialisiert wird, werden Änderungen am finalFeld möglicherweise nicht beobachtet, da die Verwendung dieses finalFelds zur Kompilierungszeit durch die Kompilierungszeitkonstante ersetzt wird.
Ein weiteres Problem besteht darin, dass die Spezifikation eine aggressive Optimierung von finalFeldern ermöglicht. Innerhalb eines Threads ist es zulässig, Lesevorgänge eines finalFeldes 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 booleanGrundelement 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.FINALaus 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 ?