En supposant que non SecurityManager
vous empêche de le faire, vous pouvez utiliser setAccessible
pour vous déplacer private
et réinitialiser le modificateur pour vous en débarrasser final
, et modifier réellement un private static final
champ.
Voici un exemple:
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"
}
}
En supposant que non SecurityException
est levé, le code ci-dessus s'imprime "Everything is true"
.
Ce qui est réellement fait ici est le suivant:
- Les
boolean
valeurs primitives true
et false
in main
sont automatiquement encadrées pour faire référence aux Boolean
constantes de type Boolean.TRUE
etBoolean.FALSE
- La réflexion est utilisée pour changer la
public static final Boolean.FALSE
faire référence à la Boolean
cité parBoolean.TRUE
- En conséquence, par la suite chaque fois qu'un
false
est autoboxed à Boolean.FALSE
, elle fait référence à la même Boolean
que celle référée parBoolean.TRUE
- Tout ce qui était
"false"
maintenant est"true"
Questions connexes
Avertissements
Un soin extrême doit être pris chaque fois que vous faites quelque chose comme ça. Cela peut ne pas fonctionner car un SecurityManager
peut être présent, mais même si ce n'est pas le cas, selon le modèle d'utilisation, cela peut ou peut ne pas fonctionner.
JLS 17.5.3 Modification ultérieure des champs finaux
Dans certains cas, comme la désérialisation, le système devra modifier les final
champs d'un objet après la construction. final
les champs peuvent être modifiés via la réflexion et d'autres moyens dépendant de la mise en œuvre. Le seul modèle dans lequel cela a une sémantique raisonnable est celui dans lequel un objet est construit et ensuite les final
champs de l'objet sont mis à jour. L'objet ne doit pas être rendu visible aux autres threads, et les final
champs ne doivent pas être lus jusqu'à ce que toutes les mises à jour des final
champs de l'objet soient terminées. Les blocages d'un final
champ se produisent à la fois à la fin du constructeur dans lequel le final
champ est défini et immédiatement après chaque modification d'un final
champ via la réflexion ou un autre mécanisme spécial.
Même alors, il y a un certain nombre de complications. Si un final
champ est initialisé à une constante de temps de compilation dans la déclaration de champ, les modifications apportées au final
champ peuvent ne pas être observées, car les utilisations de ce final
champ sont remplacées au moment de la compilation par la constante de temps de compilation.
Un autre problème est que la spécification permet une optimisation agressive des final
champs. Au sein d'un thread, il est possible de réorganiser les lectures d'un final
champ avec les modifications d'un champ final qui n'ont pas lieu dans le constructeur.
Voir également
- JLS 15.28 Expression constante
- Il est peu probable que cette technique fonctionne avec une primitive
private static final boolean
, car elle est inlineable comme constante de temps de compilation et donc la "nouvelle" valeur peut ne pas être observable
Annexe: sur la manipulation au niveau du bit
Essentiellement,
field.getModifiers() & ~Modifier.FINAL
désactive le bit correspondant à Modifier.FINAL
from field.getModifiers()
. &
est le bit à bit et et ~
est le complément au bit.
Voir également
N'oubliez pas les expressions constantes
Vous ne parvenez toujours pas à résoudre ce problème?, Êtes tombé dans la dépression comme je l'ai fait pour cela? Votre code ressemble à ceci?
public class A {
private final String myVar = "Some Value";
}
En lisant les commentaires sur cette réponse, en particulier celle de @Pshemo, cela m'a rappelé que les expressions constantes sont traitées différemment, il sera donc impossible de la modifier. Par conséquent, vous devrez modifier votre code pour qu'il ressemble à ceci:
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
si vous n'êtes pas le propriétaire de la classe ... je vous sens!
Pour plus de détails sur la raison de ce comportement, lisez ceci ?