Solución:
Asumiendo que no SecurityManager
te está impidiendo hacer esto, puedes usar setAccessible
para moverse private
y restableciendo el modificador para deshacerse de final
y modificar un private static final
campo.
He aquí un ejemplo:
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"
Asumiendo que no SecurityException
se lanza, el código anterior se imprime "Everything is true"
.
Lo que realmente se hace aquí es el siguiente:
- El primitivo
boolean
valorestrue
yfalse
enmain
están encasillados automáticamente con el tipo de referenciaBoolean
“constantes”Boolean.TRUE
yBoolean.FALSE
- La reflexión se utiliza para cambiar el
public static final Boolean.FALSE
para referirse a laBoolean
referido porBoolean.TRUE
- Como resultado, posteriormente, siempre que un
false
está autoencuadrado aBoolean.FALSE
, se refiere al mismoBoolean
como el referido porBoolean.TRUE
- Todo lo que fue
"false"
ahora es"true"
Preguntas relacionadas
- Usando la reflexión para cambiar
static final File.separatorChar
para pruebas unitarias - ¿Cómo limitar setAccessible solo a usos “legítimos”?
- Tiene ejemplos de jugar con
Integer
caché, mutando unString
, etc
- Tiene ejemplos de jugar con
Advertencias
Se debe tener mucho cuidado siempre que haga algo como esto. Puede que no funcione porque un SecurityManager
puede estar presente, pero incluso si no lo hace, dependiendo del patrón de uso, puede o no funcionar.
JLS 17.5.3 Modificación posterior de los campos finales
En algunos casos, como la deserialización, el sistema deberá cambiar la
final
campos de un objeto después de la construcción.final
Los campos se pueden cambiar mediante la reflexión y otros medios dependientes de la implementación. El único patrón en el que esto tiene una semántica razonable es uno en el que se construye un objeto y luego elfinal
Los campos del objeto se actualizan. El objeto no debe hacerse visible para otros hilos, ni elfinal
que se lean los campos, hasta que se actualicen todas lasfinal
Los campos del objeto están completos. Congelaciones de unfinal
El campo ocurre tanto al final del constructor en el que elfinal
se establece el campo, e inmediatamente después de cada modificación de unfinal
campo mediante reflexión u otro mecanismo especial.Incluso entonces, hay una serie de complicaciones. Si un
final
el campo se inicializa a una constante de tiempo de compilación en la declaración de campo, cambia alfinal
campo puede no ser observado, ya que los usos de esefinal
los campos se reemplazan en tiempo de compilación con la constante de tiempo de compilación.Otro problema es que la especificación permite una optimización agresiva de
final
los campos. Dentro de un hilo, está permitido reordenar las lecturas de unfinal
field con aquellas modificaciones de un campo final que no se producen en el constructor.
Ver también
- Expresión constante JLS 15.28
- Es poco probable que esta técnica funcione con un primitivo
private static final boolean
, porque se puede incorporar como una constante en tiempo de compilación y, por lo tanto, es posible que el valor “nuevo” no sea observable
- Es poco probable que esta técnica funcione con un primitivo
Apéndice: Sobre la manipulación bit a bit
Esencialmente,
field.getModifiers() & ~Modifier.FINAL
apaga el bit correspondiente a Modifier.FINAL
de field.getModifiers()
. &
es el bit a bit-and, y ~
es el complemento bit a bit.
Ver también
- Wikipedia / operación bit a bit
Recuerde Expresiones Constantes
¿Sigues sin poder solucionar esto ?, ¿has caído en la depresión como yo lo hice por ello? ¿Tu código se ve así?
public class A
private final String myVar = "Some Value";
Al leer los comentarios sobre esta respuesta, especialmente la de @Pshemo, me recordó que las Expresiones constantes se manejan de manera diferente, por lo que será imposible para modificarlo. Por lo tanto, deberá cambiar su código para que se vea así:
public class A
private final String myVar;
private A()
myVar = "Some Value";
si no eres el dueño de la clase … te siento!
Para obtener más detalles sobre por qué este comportamiento, lea esto.
Si el valor asignado a un static final boolean
El campo se conoce en tiempo de compilación, es un constante. Campos de primitivo o
String
type pueden ser constantes en tiempo de compilación. Se incluirá una constante en cualquier código que haga referencia al campo. Dado que el campo no se lee realmente en tiempo de ejecución, cambiarlo no tendrá ningún efecto.
La especificación del lenguaje Java dice esto:
Si un campo es una variable constante (§4.12.4), eliminar la palabra clave final o cambiar su valor no romperá la compatibilidad con binarios preexistentes al hacer que no se ejecuten, pero no verán ningún valor nuevo para el uso del campo a menos que se vuelvan a compilar. Este es true incluso si el uso en sí no es una expresión constante en tiempo de compilación (§15.28)
He aquí un ejemplo:
class Flag
static final boolean FLAG = true;
class Checker
public static void main(String... argv)
System.out.println(Flag.FLAG);
Si descompila Checker
, verá que en lugar de hacer referencia Flag.FLAG
, el código simplemente empuja un valor de 1 (true
) en la pila (instrucción n. ° 3).
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_1
4: invokevirtual #3; //Method java/io/PrintStream.println:(Z)V
7: return
Un poco de curiosidad sobre la Especificación del lenguaje Java, capítulo 17, sección 17.5.4 “Campos protegidos contra escritura”:
Normalmente, un campo que es final y static no puede modificarse. Sin embargo, System.in, System.out y System.err son static campos finales que, por razones heredadas, deben poder modificarse mediante los métodos System.setIn, System.setOut y System.setErr. Nos referimos a estos campos como protegidos contra escritura para distinguirlos de los campos finales ordinarios.
Fuente: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.4
Acuérdate de que te concedemos esclarecer si te fue de ayuda.