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.
Is it possible in Java to access private fields via reflection - Stack Overflow
Java class: Why do you make fields private?
java - Set Value of Private Static Field - Stack Overflow
Setting private fields using Java Reflection - Stack Overflow
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
If I were to make public getters and setters to access those private fields of a class, why not just make those fields public from the beginning? If I make them public from the beginning, I don't have to have getters and setters and make the code simple, right?
Basically the problem is your utility method, which assumes you have an instance. It's reasonably easy to set a private static field - it's exactly the same procedure as for an instance field, except you specify null as the instance. Unfortunately your utility method uses the instance to get the class, and requires it to be non-null...
I'd echo Tom's caveat: don't do that. If this is a class you have under your control, I'd create a package level method:
void setFooForTesting(Bar newValue)
{
foo = newValue;
}
However, here's a complete sample if you really, really want to set it with reflection:
import java.lang.reflect.*;
class FieldContainer
{
private static String woot;
public static void showWoot()
{
System.out.println(woot);
}
}
public class Test
{
// Declared to throw Exception just for the sake of brevity here
public static void main(String[] args) throws Exception
{
Field field = FieldContainer.class.getDeclaredField("woot");
field.setAccessible(true);
field.set(null, "New value");
FieldContainer.showWoot();
}
}
Just pass null for the object-instance argument. So:
field.set(null, p_fieldValue);
This will let you set the static field.
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);