简体   繁体   中英

Java—how can I dynamically reference an object's property?

In javascript, I can do this:

function MyObject(obj) {
    for (var property in obj) {
        this[property] = obj[property];
    }
}

Can I do anything close in Java?

class MyObject {
    String myProperty;

    public MyObject(HashMap<String, String> props) {
        // for each key in props where the key is also the name of
        // a property in MyObject, can I assign the value to this.[key]?
    }
}

Not that I disagree with Joel's answer, but I do not think it is not quite that difficult, if you essentially just want a best effort. Essentially check if it is there, and if it is try to set. If it works great if not, oh well we tried. For example:

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class MyObject {

    protected String lorem;
    protected String ipsum;
    protected int integer;


    public MyObject(Map<String, Object> valueMap){
        for (String key : valueMap.keySet()){
            setField(key, valueMap.get(key));
        }
    }

    private void setField(String fieldName, Object value) {
        Field field;
        try {
            field = getClass().getDeclaredField(fieldName);
            field.set(this, value);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Map<String, Object> valueMap = new HashMap<String, Object>();
        valueMap.put("lorem", "lorem Value");
        valueMap.put("ipsum", "ipsum Value");
        valueMap.put("integer", 100);
        valueMap.put("notThere", "Nope");

        MyObject f = new MyObject(valueMap);
        System.out.println("lorem => '"+f.lorem+"'");
        System.out.println("ipsum => '"+f.ipsum+"'");
        System.out.println("integer => '"+f.integer+"'");
    }
}

These answers all suck, so I felt like doing the world a favor and adding a decent answer. First, I would use a map if at all possible :

class MyObject {

     // String myProperty; // ! not this
     HashMap<String,String> myProperties;  // use this instead

}

but let's say you wanted to set the fields dynamically.

public MyObject(HashMap<String, String> props) {
    for (Map.Entry<String,String> entry : props.entrySet()) {
        Field field = this.getClass().getField(entry.getKey());
        field.set(this, entry.getValue());
    }
}

of course, you will want to use a try/catch in the above constructor.

Yes, you can do it by reflection with something along the following lines:

/**
 * Returns a list of all Fields in this object, including inherited fields.
 */
private List<Field> getFields() {
    List<Field> list = new ArrayList<Field>();
    getFields(list, getClass());
    return list;
}

/**
 * Adds the fields of the provided class to the List of Fields. 
 * Recursively adds Fields also from super classes.
 */
private List<Field> getFields(List<Field> list, Class<?> startClass) {
    for (Field field : startClass.getDeclaredFields()) {
        list.add(field);
    }
    Class<?> superClass = startClass.getSuperclass();
    if(!superClass.equals(Object.class)) {
        getFields(list, superClass);
    }
}

public void setParameters(Map<String, String> props) throws IllegalArgumentException, IllegalAccessException {
    for(Field field : getFields()) {
        if (props.containsKey(field.getName())) {
            boolean prevAccessible = field.isAccessible();
            if (!prevAccessible) {
                /*
                 * You're not allowed to modify this field. 
                 * So first, you modify it to make it modifiable.
                 */
                field.setAccessible(true);
            }
            field.set(this, props.get(field.getName()));

            /* Restore the mess you made */
            field.setAccessible(prevAccessible);
        }
    }
}

However, if you are not very familiar with Java, this approach should be avoided if at all possible, as it is somewhat dangerous and error prone. For instance, there is no guarantee that the Field you are attempting to set are actually expecting a String. If it is the case that they are not, your program will crash and burn.

好吧,如果你真的想要反思raod,那么我建议看看Introspector类并从BeanInfo获取PropertyDescriptors列表。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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