简体   繁体   English

使用反射设置私有字段值

[英]Set private field value with reflection

I have 2 classes: Father and Child我有 2 个班级: FatherChild

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:通过反射,我想在Child类中设置a_field

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线程“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:使用 setter 方法我有同样的问题:

method = cc.getClass().getMethod("setA_field");
method.invoke(cc, new Object[] { "aaaaaaaaaaaaaa" });

To access a private field you need to set Field::setAccessible to true.要访问私有字段,您需要将Field::setAccessible设置为 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);

Using FieldUtils from the Apache Commons Lang 3 :使用Apache Commons Lang 3 中的FieldUtils

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

The true forces it to set, even if the field is private .即使该字段是privatetrue也会强制设置它。

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);

Kotlin verison Kotlin 版本

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");

You can use Manifold's @Jailbreak for direct, type-safe Java reflection:您可以使用Manifold 的@Jailbreak进行直接的、类型安全的 Java 反射:

@Jailbreak Child child = new Child();
child.a_field = "123;

@Jailbreak unlocks the child local variable in the compiler for direct access to all the members in Child 's hierarchy. @Jailbreak在编译器中解锁子局部变量,以便直接访问Child层次结构中的所有成员。

Similarly you can use the jailbreak() extension method for one-off use:同样,您可以使用jailbreak()扩展方法进行一次性使用:

child.jailbreak().a_field = "123";

Through the jailbreak() method you can access any member in Child 's hierarchy.通过jailbreak()方法,您可以访问Child层次结构中的任何成员。

In both cases the compiler resolves the field access for you type-safely, as if a public field, while Manifold generates efficient reflection code for you under the hood.在这两种情况下,编译器都会以类型安全的方式为您解析字段访问,就像公共字段一样,而 Manifold 会在幕后为您生成高效的反射代码。

Discover more about Manifold .了解更多关于歧管的信息

As per the Javadoc of Class.getField (emphasis mine):根据Class.getField的 Javadoc(重点是我的):

Returns a Field object that reflects the specified public member field of the class or interface represented by this Class object.返回一个 Field 对象,该对象反映了此 Class 对象表示的类或接口的指定公共成员字段

This method only returns public fields.此方法仅返回公共字段。 Since a_field is private, it won't be found.由于a_field是私有的,因此不会被找到。

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());请注意,我还更改了您的行String str1 = (String) f1.get(cc.getClass()); to String str1 = (String) f1.get(cc); 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.如果你想保持你的字段私有,那么你需要检索 getter / setter 方法并调用它们。 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM