java-如何使用反射更新层次结构中的成员

java-如何使用反射更新层次结构中的成员,java,reflection,Java,Reflection,我有一个名为沃尔沃的课程,它继承了汽车。 它包含一个名为Engine的类,该类包含Valve public class Engine { public Engine(int e, int f) { this.e = e; valve = new Valve(f); } private int e; private Valve valve; } 阀门有一个单一的数据成员-int f public class Valve {

我有一个名为沃尔沃的课程,它继承了汽车。
它包含一个名为Engine的类,该类包含Valve

public class Engine {

    public Engine(int e, int f) {
        this.e = e;
        valve = new Valve(f);
    }

    private int e;
    private Valve valve;
}
阀门有一个单一的数据成员-int f

public class Valve {
    public Valve(int f) {
        this.f = f;
    }

    public int f;
}
所有内容都是私有的,不包含setter

我想使用反射和以下字符串设置一个值

fillIn(volvo, "Engine.Valve.f", 10);
使用此代码:

String[] splits = path.split("\\.");
Class tmpClass = obj.getClass();

for (int i = 0; i < splits.length; i++) {
    if (i + 1 != splits.length) {
        Field field = tmpClass.getDeclaredField(splits[i]);
        tmpClass = field.getClass();
    } else {
        System.out.println("**** - " + splits[i]);
    }
}
String[]splits=path.split(“\\”);
类tmpClass=obj.getClass();
对于(int i=0;i
问题:
1.我的目标是沃尔沃。发动机位于汽车的底部。我可以在迭代沃尔沃时获得字段吗
2.如何设置该值?类型每次都不一样
3.有没有更好的实践(FW?)可以做到这一点


谢谢。

要访问私有字段,您可以在字段上设置访问权限为
true
,如下所示:

field.setAccessible(true);
看看这个例子:

和javadoc

顺便说一句,使用setter肯定会更好
编辑:
您需要存储要设置的字段的对象:
由javadoc编写、未经测试的位编辑代码

String[] splits = path.split("\\.");
Class tmpClass = obj.getClass();
Object tmpObject = obj;

for (int i = 0; i < splits.length; i++) {
    if (i + 1 != splits.length) {
        Field field = tmpClass.getDeclaredField(splits[i]);
        tmpClass = field.getClass();
        if(tmpClass.equals(Integer.class)){
            field.setInt(tmpObject,42); //where 42 is the number to set
            return;
        }
        tmpObject = field.get(tmpObject); // tmpObject contais the object to set
    }
}
String[]splits=path.split(“\\”);
类tmpClass=obj.getClass();
对象tmpObject=obj;
对于(int i=0;i

也许代码不起作用,但我希望它显示出您的想法

您正朝着正确的方向前进,但是您的代码中有几个问题:

  • 正如您已经发现的,
    getDeclaredField
    将为您获取一个字段,如果它是在您调用它的类中声明的,而不是在超类中声明的。但是,您可以使用
    NoSuchFieldException
    ,如果当前类中未声明字段,则会抛出该异常,以获取超类并重试
  • 尝试通过反射获取字段时,传递给
    getDeclaredField
    方法的值区分大小写。这意味着您需要调用
    fillIn
    方法作为
    fillIn(volvo,“engine.valve.f”,10)因为沃尔沃类(通过继承汽车类)有一个名为
    引擎
    的字段,而不是
    引擎
  • tmpClass=field.getClass()
    将检索
    字段
    对象的类,当然是
    字段
    。您要做的是检索由
    field
    表示的声明字段的类型,这可以通过
    field.getType()
    完成
  • 因此,您的代码变为:

    private void fillIn(Object obj, String path, int number) throws Exception {
        String[] splits = path.split("\\.");
        Class tmpClass = obj.getClass();
    
        for (int i = 0; i < splits.length; i++) {
            if (i + 1 != splits.length) {
                Field field = null;
                while ((field == null) && (tmpClass != null)) {
                    try {
                        field = tmpClass.getDeclaredField(splits[i]);
                    } catch (NoSuchFieldException ex) {
                        tmpClass = tmpClass.getSuperclass();
                    }
                }
                tmpClass = field.getType();
            } else {
                System.out.println("**** - " + splits[i]);
            }
        }
    }
    
    private void fillIn(对象对象对象、字符串路径、整数)引发异常{
    String[]splits=path.split(“\\”);
    类tmpClass=obj.getClass();
    对于(int i=0;i
    我解决了这个问题,不需要访问级别或getter&setter,使用
    (这需要重新编写,用于生产+当前只解决int)

    私有静态空白填充(对象对象对象、字符串路径、int值){
    对象tempObj=obj;
    反射数据反射数据;
    if(路径包含(“.”){
    String[]splits=path.split(“\\”);
    对于(int i=0;i
    在哪里

    公共类ReflectionData{

    public ReflectionData(Class<?> aClass, Field field, Object object) {
        this.aClass = aClass;
        this.field = field;
        this.object = object;
    }
    
    public Class<?> aClass;
    public Field field;
    public Object object;
    
    public Object getFieldObject() {
        Object o = null;
        try {
            o = field.get(object);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return o;
    }
    
    public void setFieldObject(int value) {
        try {
            field.set(object, value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    
    public ReflectionData(类aClass、字段、对象){
    this.aClass=aClass;
    this.field=字段;
    this.object=对象;
    }
    公共类aClass;
    公共领域;
    公共客体;
    公共对象getFieldObject(){
    对象o=null;
    试一试{
    o=field.get(对象);
    }捕获(非法访问例外e){
    e、 printStackTrace();
    }
    返回o;
    }
    公共无效setFieldObject(int值){
    试一试{
    设置字段(对象、值);
    }捕获(非法访问例外e){
    e、 printStackTrace();
    }
    }
    

    }

    另一个答案表明,如果使用getter和setter,这将多么容易

    // Assuming that the Volvo class builds it own engine,
    // with the Engine class building its own value.
    Car volvo = new Volvo();
    int newF = 10;
    
    volvo.getEngine().getValve().setF(newF); // Done
    

    为什么要避免使用setter和getter?问题很简单,为什么更容易?请看我的答案。会更多吗
    // Assuming that the Volvo class builds it own engine,
    // with the Engine class building its own value.
    Car volvo = new Volvo();
    int newF = 10;
    
    volvo.getEngine().getValve().setF(newF); // Done