117

I have 2 classes: Father and Child

public class Father implements Serializable, JSONInterface {

    private String a_field;

    //setter and getter here

}

public class Child extends Father {
    //empty class
}

With reflection I want to set a_field in Child class:

Class<?> clazz = Class.forName("Child");
Object cc = clazz.newInstance();

Field f1 = cc.getClass().getField("a_field");
f1.set(cc, "reflecting on life");
String str1 = (String) f1.get(cc.getClass());
System.out.println("field: " + str1);

but I have an exception:

Exception in thread "main" java.lang.NoSuchFieldException: a_field

But if I try:

Child child = new Child();
child.setA_field("123");

it works.

Using setter method I have same problem:

method = cc.getClass().getMethod("setA_field");
method.invoke(cc, new Object[] { "aaaaaaaaaaaaaa" });
Tunaki
  • 132,869
  • 46
  • 340
  • 423
user1066183
  • 2,444
  • 4
  • 28
  • 57
  • 3
    You need to get the superclass of the Class first, before beeing able to acces the field. [another SO question](http://stackoverflow.com/questions/3567372/access-to-private-inherited-fields-via-reflection-in-java) – SomeJavaGuy Sep 22 '15 at 12:34
  • 1
    The field is not part of the Child class Since it is private, it is not even visible in the Child class.The setters are public and are inherited, which means they can be called as if they were declared in the Child class. – f1sh Sep 22 '15 at 12:37
  • Instead of retrieving the field which is private,set its value by retrieving its setter Method – Manas Pratim Chamuah Sep 22 '15 at 12:40
  • Yes, it is a good solution. Now I can try – user1066183 Sep 22 '15 at 12:41

5 Answers5

181

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:

Class<?> 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);
Ivar
  • 6,138
  • 12
  • 49
  • 61
John McClean
  • 5,225
  • 1
  • 22
  • 30
136

Using FieldUtils from the Apache Commons Lang 3:

FieldUtils.writeField(childInstance, "a_field", "Hello", true);

The true forces it to set, even if the field is private.

informatik01
  • 16,038
  • 10
  • 74
  • 104
David Lavender
  • 8,021
  • 3
  • 35
  • 55
18

Kotlin verison

Get private variable using below extension functions

fun <T : Any> T.getPrivateProperty(variableName: String): Any? {
    return javaClass.getDeclaredField(variableName).let { field ->
        field.isAccessible = true
        return@let field.get(this)
    }
}

Set private variable value get the variable

fun <T : Any> T.setAndReturnPrivateProperty(variableName: String, data: Any): Any? {
    return javaClass.getDeclaredField(variableName).let { field ->
        field.isAccessible = true
        field.set(this, data)
        return@let field.get(this)
    }
}

Get variable use:

val bool = <your_class_object>.getPrivateProperty("your_variable") as String

Set and get variable use:

val bool = <your_class_object>.setAndReturnPrivateProperty("your_variable", true) as Boolean
val str = <your_class_object>.setAndReturnPrivateProperty("your_variable", "Hello") as String

Java version

public class RefUtil {

    public static Field setFieldValue(Object object, String fieldName, Object valueTobeSet) throws NoSuchFieldException, IllegalAccessException {
        Field field = getField(object.getClass(), fieldName);
        field.setAccessible(true);
        field.set(object, valueTobeSet);
        return field;
    }

    public static Object getPrivateFieldValue(Object object, String fieldName) throws NoSuchFieldException, IllegalAccessException {
        Field field = getField(object.getClass(), fieldName);
        field.setAccessible(true);
        return field.get(object);
    }

    private static Field getField(Class mClass, String fieldName) throws NoSuchFieldException {
        try {
            return mClass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            Class superClass = mClass.getSuperclass();
            if (superClass == null) {
                throw e;
            } else {
                return getField(superClass, fieldName);
            }
        }
    }
}

Set private value use

RefUtil.setFieldValue(<your_class_object>, "your_variableName", newValue);

Get private value use

Object value = RefUtil.getPrivateFieldValue(<your_class_object>, "your_variableName");
akhilesh0707
  • 6,709
  • 5
  • 44
  • 51
6

This one can access private fields as well without having to do anything

import org.apache.commons.lang3.reflect.FieldUtils;
Object value = FieldUtils.readField(entity, fieldName, true);
Sacky San
  • 1,535
  • 21
  • 26
-5

As per the Javadoc of Class.getField (emphasis mine):

Returns a Field object that reflects the specified public member field of the class or interface represented by this Class object.

This method only returns public fields. Since a_field is private, it won't be found.

Here's a working code:

public class Main {

    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("Child");
        Object cc = clazz.newInstance();

        Field f1 = cc.getClass().getField("a_field");
        f1.set(cc, "reflecting on life");
        String str1 = (String) f1.get(cc);
        System.out.println("field: " + str1);
    }

}

class Father implements Serializable {
    public String a_field;
}

class Child extends Father {
//empty class
}

Note that I also changed your line String str1 = (String) f1.get(cc.getClass()); to String str1 = (String) f1.get(cc); because you need to give the object of the field, not the class.


If you want to keep your field private, then you need to retrieve the getter / setter method and invoke those instead. The code you have given does not work because, to get a method, you also need to specify it's arguments, so

cc.getClass().getMethod("setA_field");

must be

cc.getClass().getMethod("setA_field", String.class);

Here's a working code:

public class Main {

    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("Child");
        Object cc = clazz.newInstance();
        cc.getClass().getMethod("setA_field", String.class).invoke(cc, "aaaaaaaaaaaaaa");
        String str1 = (String) cc.getClass().getMethod("getA_field").invoke(cc);
        System.out.println("field: " + str1);
    }

}

class Father implements Serializable {

    private String a_field;

    public String getA_field() {
        return a_field;
    }

    public void setA_field(String a_field) {
        this.a_field = a_field;
    }

}

class Child extends Father {
    //empty class
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423