To access a private field you need to set Field::setAccessible to true. You can pull the field off the super class. This code works:
CopyClass<?> clazz = Child.class;
Object cc = clazz.newInstance();
Field f1 = cc.getClass().getSuperclass().getDeclaredField("a_field");
f1.setAccessible(true);
f1.set(cc, "reflecting on life");
String str1 = (String) f1.get(cc);
System.out.println("field: " + str1);
Answer from John McClean on Stack OverflowTo access a private field you need to set Field::setAccessible to true. You can pull the field off the super class. This code works:
CopyClass<?> clazz = Child.class;
Object cc = clazz.newInstance();
Field f1 = cc.getClass().getSuperclass().getDeclaredField("a_field");
f1.setAccessible(true);
f1.set(cc, "reflecting on life");
String str1 = (String) f1.get(cc);
System.out.println("field: " + str1);
Using FieldUtils from the Apache Commons Lang 3:
CopyFieldUtils.writeField(childInstance, "a_field", "Hello", true);
The true forces it to set, even if the field is private.
Yes, it absolutely is - assuming you've got the appropriate security permissions. Use Field.setAccessible(true) first if you're accessing it from a different class.
import java.lang.reflect.*;
class Other
{
private String str;
public void setStr(String value)
{
str = value;
}
}
class Test
{
public static void main(String[] args)
// Just for the ease of a throwaway test. Don't
// do this normally!
throws Exception
{
Other t = new Other();
t.setStr("hi");
Field field = Other.class.getDeclaredField("str");
field.setAccessible(true);
Object value = field.get(t);
System.out.println(value);
}
}
And no, you shouldn't normally do this... it's subverting the intentions of the original author of the class. For example, there may well be validation applied in any situation where the field can normally be set, or other fields may be changed at the same time. You're effectively violating the intended level of encapsulation.
Yes.
Field f = Test.class.getDeclaredField("str");
f.setAccessible(true);//Very important, this allows the setting to work.
String value = (String) f.get(object);
Then you use the field object to get the value on an instance of the class.
Note that get method is often confusing for people. You have the field, but you don't have an instance of the object. You have to pass that to the get method
Get all the methods and find the matching one, which has type info about the parameters:
String name;
String value;
Method[] methods = Child.class.getMethods();
for (Method method : methods) {
if (!method.getName().equals(name))
continue;
Class<?> paramType = method.getParameterTypes()[0];
//You will have to figure how to convert the String value to the parameter.
method.invoke(child, paramType.cast(value)); // for example
}
You could use Apache Commons FieldUtils.writeDeclaredField
Child childObject = new Child();
FieldUtils.writeDeclaredField(childObject, "name", "John", true);
This answer is more than exhaustive on the topic.
JLS 17.5.3 Subsequent Modification of Final Fields
Even then, there are a number of complications. If a final field is initialized to a compile-time constant in the field declaration, changes to the final field may not be observed, since uses of that final field are replaced at compile time with the compile-time constant.
But, if you read the paragraph above very carefully, you may find a way around here (set the private final field in the constructor instead of in the field definition):
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws Exception {
WithPrivateFinalField pf = new WithPrivateFinalField();
System.out.println(pf);
Field f = pf.getClass().getDeclaredField("s");
f.setAccessible(true);
System.out.println("f.get(pf): " + f.get(pf));
f.set(pf, "No, you’re not!");
System.out.println(pf);
System.out.println("f.get(pf): " + f.get(pf));
}
private static class WithPrivateFinalField {
private final String s;
public WithPrivateFinalField() {
this.s = "I’m totally safe";
}
public String toString() {
return "s = " + s;
}
}
}
The output is then as follows:
s = I’m totally safe
f.get(pf): I’m totally safe
s = No, you’re not!
f.get(pf): No, you’re not!
Hope this helps a bit.
This
class WithPrivateFinalField {
private final String s = "I’m totally safe";
public String toString() {
return "s = " + s;
}
}
actually compiles like this:
class WithPrivateFinalField {
private final String s = "I’m totally safe";
public String toString() {
return "s = I’m totally safe";
}
}
That is, compile-time constants get inlined. See this question. The easiest way to avoid inlining is to declare the String like this:
private final String s = "I’m totally safe".intern();
For other types, a trivial method call does the trick:
private final int integerConstant = identity(42);
private static int identity(int number) {
return number;
}
Assuming no SecurityManager is preventing you from doing this, you can use setAccessible to get around private and resetting the modifier to get rid of final, and actually modify a private static final field.
Here's an example:
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"
}
}
Assuming no SecurityException is thrown, the above code prints "Everything is true".
What's actually done here is as follows:
- The primitive
booleanvaluestrueandfalseinmainare autoboxed to reference typeBoolean"constants"Boolean.TRUEandBoolean.FALSE - Reflection is used to change the
public static final Boolean.FALSEto refer to theBooleanreferred to byBoolean.TRUE - As a result, subsequently whenever a
falseis autoboxed toBoolean.FALSE, it refers to the sameBooleanas the one refered to byBoolean.TRUE - Everything that was
"false"now is"true"
Related questions
- Using reflection to change
static final File.separatorCharfor unit testing - How to limit setAccessible to only “legitimate” uses?
- Has examples of messing with
Integer's cache, mutating aString, etc
- Has examples of messing with
Caveats
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.
JLS 17.5.3 Subsequent Modification of Final Fields
In some cases, such as deserialization, the system will need to change the
finalfields of an object after construction.finalfields can be changed via reflection and other implementation dependent means. The only pattern in which this has reasonable semantics is one in which an object is constructed and then thefinalfields of the object are updated. The object should not be made visible to other threads, nor should thefinalfields be read, until all updates to thefinalfields of the object are complete. Freezes of afinalfield occur both at the end of the constructor in which thefinalfield is set, and immediately after each modification of afinalfield via reflection or other special mechanism.Even then, there are a number of complications. If a
finalfield is initialized to a compile-time constant in the field declaration, changes to thefinalfield may not be observed, since uses of thatfinalfield are replaced at compile time with the compile-time constant.Another problem is that the specification allows aggressive optimization of
finalfields. Within a thread, it is permissible to reorder reads of afinalfield with those modifications of a final field that do not take place in the constructor.
See also
- JLS 15.28 Constant Expression
- It's unlikely that this technique works with a primitive
private static final boolean, because it's inlineable as a compile-time constant and thus the "new" value may not be observable
- It's unlikely that this technique works with a primitive
Appendix: On the bitwise manipulation
Essentially,
field.getModifiers() & ~Modifier.FINAL
turns off the bit corresponding to Modifier.FINAL from field.getModifiers(). & is the bitwise-and, and ~ is the bitwise-complement.
See also
- Wikipedia/Bitwise operation
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?
public class A {
private final String myVar = "Some Value";
}
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:
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
if you are not the owner of the class... I feel you!
For more details about why this behavior read this?
If the value assigned to a static final boolean field is known at compile-time, it is a constant. Fields of primitive or
String 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:
If a field is a constant variable (§4.12.4), then deleting the keyword final or changing its value will not break compatibility with pre-existing binaries by causing them not to run, but they will not see any new value for the usage of the field unless they are recompiled. This is true even if the usage itself is not a compile-time constant expression (§15.28)
Here's an example:
class Flag {
static final boolean FLAG = true;
}
class Checker {
public static void main(String... argv) {
System.out.println(Flag.FLAG);
}
}
If you decompile Checker, you'll see that instead of referencing Flag.FLAG, the code simply pushes a value of 1 (true) onto the stack (instruction #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