Unter der Annahme, dass keine SecurityManager
Sie daran hindert, können Sie mit setAccessible
um sich fortzubewegen private
und das Zurücksetzen des Modifikators, um die final
und ändern Sie tatsächlich eine 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"
}
}
Unter der Annahme, dass keine SecurityException
ausgelöst wird, gibt der obige Code Folgendes aus "Everything is true"
.
Was hier tatsächlich geschieht, ist Folgendes:
- Das Primitive
boolean
Werte true
y false
sur main
auf den Referenztyp autoboxed sind Boolean
"Konstanten" Boolean.TRUE
y Boolean.FALSE
- Die Reflexion dient der Veränderung der
public static final Boolean.FALSE
um auf den Boolean
genannt von Boolean.TRUE
- Infolgedessen wird jedes Mal, wenn ein
false
wird autoboxiert an Boolean.FALSE
bezieht sie sich auf dieselbe Boolean
als die, auf die sich die Boolean.TRUE
- Alles, was war
"false"
jetzt ist "true"
Verwandte Fragen
Vorbehalte
Wenn Sie so etwas tun, sollten Sie äußerst vorsichtig sein. Es kann sein, dass es nicht funktioniert, weil ein SecurityManager
vorhanden sein, aber auch wenn dies nicht der Fall ist, kann es je nach Nutzungsmuster funktionieren oder auch nicht.
JLS 17.5.3 Nachträgliche Änderung der endgültigen Felder
In einigen Fällen, etwa bei der Deserialisierung, muss das System die final
Felder eines Objekts nach der Konstruktion. final
Felder können über Reflexion und andere implementierungsabhängige Mittel geändert werden. Das einzige Muster, bei dem dies eine vernünftige Semantik hat, ist eines, bei dem ein Objekt konstruiert wird und dann die final
Felder des Objekts aktualisiert werden. Das Objekt sollte weder für andere Threads sichtbar gemacht werden, noch sollte die final
Felder gelesen werden, bis alle Aktualisierungen der final
Felder des Objekts vollständig sind. Das Einfrieren eines final
treten sowohl am Ende des Konstruktors auf, in dem die final
gesetzt wird, und unmittelbar nach jeder Änderung eines final
Feld durch Reflexion oder einen anderen speziellen Mechanismus.
Selbst dann gibt es eine Reihe von Komplikationen. Wenn ein final
Feld in der Felddeklaration mit einer Kompilierzeitkonstante initialisiert wird, werden Änderungen an der final
Feldes darf nicht beachtet werden, da die Verwendung dieses final
werden zur Kompilierzeit durch die Kompilierzeitkonstante ersetzt.
Ein weiteres Problem ist, dass die Spezifikation eine aggressive Optimierung der final
Felder. Innerhalb eines Threads ist es zulässig, die Reihenfolge der Lesevorgänge eines final
mit den Änderungen eines endgültigen Feldes, die nicht im Konstruktor vorgenommen werden.
Siehe auch
- JLS 15.28 Konstante Ausdrücke
- Es ist unwahrscheinlich, dass diese Technik mit einer primitiven
private static final boolean
weil er als Kompilierzeitkonstante inlinefähig ist und der "neue" Wert daher möglicherweise nicht beobachtbar ist
Anhang: Über die bitweise Manipulation
Im Wesentlichen,
field.getModifiers() & ~Modifier.FINAL
schaltet das Bit aus, das der Modifier.FINAL
de field.getModifiers()
. &
ist das bitweise-und, und ~
ist das Bitwise-Komplement.
Siehe auch
Konstante Ausdrücke merken
Kannst du das Problem immer noch nicht lösen, bist du in eine Depression verfallen, wie ich es getan habe? Sieht Ihr Code so aus?
public class A {
private final String myVar = "Some Value";
}
Beim Lesen der Kommentare zu dieser Antwort, insbesondere des Kommentars von @Pshemo, wurde ich daran erinnert, dass Konstante Ausdrücke unterschiedlich gehandhabt werden, so dass es unmöglich um sie zu ändern. Daher müssen Sie Ihren Code so ändern, dass er wie folgt aussieht:
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
wenn Sie nicht der Eigentümer der Klasse sind... Ich fühle mit Ihnen!
Weitere Einzelheiten über die Gründe für dieses Verhalten dies lesen ?
4 Stimmen
Das ist eine schlechte Idee. Ich würde stattdessen versuchen, den Quellcode zu bekommen und neu zu kompilieren (oder sogar zu dekompilieren/neu zu kompilieren).
0 Stimmen
System.out ist ein öffentliches, statisches, endgültiges Feld, das aber auch geändert werden kann.
21 Stimmen
@irreputable
System.out/in/err
sind so "speziell", dass sie im Java Memory Model besonders erwähnt werden müssen. Sie sind keine Beispiele, denen man folgen sollte.8 Stimmen
Gut mein Punkt ws, um einen Hack in der zwischen zu finden, um meine app arbeiten, bis die Lib verantwortlich die Änderung an der nächsten Version machen, so dass ich nicht mehr hacken müssen...
6 Stimmen
@Bill K von vor zehn Jahren: Es wäre großartig, sie neu zu kompilieren, aber sie befindet sich auf einem bereitgestellten System und ich muss sie nur patchen, bis wir die bereitgestellte Anwendung aktualisieren können!
0 Stimmen
Für Java 17 Deklarierte Felder von java.lang.reflect.Fields in jdk12 abrufen