I have a class with a private static final
field that, unfortunately, I need to change at run-time.
Using reflection I get this error: java.lang.IllegalAccessException: Can not set static final boolean field
Is there any way to change the value?
Field hack = WarpTransform2D.class.getDeclaredField("USE_HACK");
hack.setAccessible(true);
hack.set(null, true);
I also integrated it with joor library
Just use
Also I fixed an issue with
override
which the previous solutions seem to miss. However use this very carefully, only when there's no other good solution.In case of presence of a Security Manager, one can make use of
AccessController.doPrivileged
Taking the same example from accepted answer above:
In lambda expression,
AccessController.doPrivileged
, can be simplified to:Assuming no
SecurityManager
is preventing you from doing this, you can usesetAccessible
to get aroundprivate
and resetting the modifier to get rid offinal
, and actually modify aprivate static final
field.Here's an example:
Assuming no
SecurityException
is thrown, the above code prints"Everything is true"
.What's actually done here is as follows:
boolean
valuestrue
andfalse
inmain
are autoboxed to reference typeBoolean
"constants"Boolean.TRUE
andBoolean.FALSE
public static final Boolean.FALSE
to refer to theBoolean
referred to byBoolean.TRUE
false
is autoboxed toBoolean.FALSE
, it refers to the sameBoolean
as the one refered to byBoolean.TRUE
"false"
now is"true"
Related questions
static final File.separatorChar
for unit testingInteger
's cache, mutating aString
, etcCaveats
Extreme care should be taken whenever you do something like this. It may not work because a
SecurityManager
may be present, but even if it doesn't, depending on usage pattern, it may or may not work.See also
private static final boolean
, because it's inlineable as a compile-time constant and thus the "new" value may not be observableAppendix: On the bitwise manipulation
Essentially,
turns off the bit corresponding to
Modifier.FINAL
fromfield.getModifiers()
.&
is the bitwise-and, and~
is the bitwise-complement.See also
Remember Constant Expressions
Still not being able to solve this?, have fallen onto depression like I did for it? Does your code looks like this?
Reading the comments on this answer, specially the one by @Pshemo, it reminded me that Constant Expressions are handled different so it will be impossible to modify it. Hence you will need to change your code to look like this:
if you are not the owner of the class... I feel you!
For more details about why this behavior read this?
The accepted answer worked for me until deployed on JDK 1.8u91. Then I realized it failed at
field.set(null, newValue);
line when I had read the value via reflection before calling ofsetFinalStatic
method.Probably the read caused somehow different setup of Java reflection internals (namely
sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl
in failing case instead ofsun.reflect.UnsafeStaticObjectFieldAccessorImpl
in success case) but I didn't elaborate it further.Since I needed to temporarily set new value based on old value and later set old value back, I changed signature little bit to provide computation function externally and also return old value:
However for general case this would not be sufficient.
If the value assigned to a
static final boolean
field is known at compile-time, it is a constant. Fields of primitive orString
type can be compile-time constants. A constant will be inlined in any code that references the field. Since the field is not actually read at runtime, changing it then will have no effect.The Java language specification says this:
Here's an example:
If you decompile
Checker
, you'll see that instead of referencingFlag.FLAG
, the code simply pushes a value of 1 (true
) onto the stack (instruction #3).Just saw that question on one of the interview question, if possible to change final variable with reflection or in runtime. Got really interested, so that what I became with:
Some simple class with final String variable. So in the main class import java.lang.reflect.Field;
The output will be as follows:
According to documentation https://docs.oracle.com/javase/tutorial/reflect/member/fieldValues.html