使用点分隔的String访问(私有)成员

时间:2016-03-10 15:03:46

标签: java reflection

我可以通过以下语法访问实例字段: student.address.city

public class Student {
   private Address address;
   //getters&setters
}

public class Address {
    private String town;
    private String street;
    private String city;
   //getters&setters
}

我认为可以使用反射以某种方式完成。 基本上我需要这样的东西:

String city = getPropertyValue("student.address.city", student);

与js一样,我们可以访问对象属性。

4 个答案:

答案 0 :(得分:4)

还有一个名为org.apache.commons.beanutils.PropertyUtils.getNestedProperty()的方法专用于此。

答案 1 :(得分:3)

使用getDeclaredField方法实际上非常简单。

但是,在开头提供student作为第一个参数,因为Java不知道你引用的student-object

void someOtherMethod() {
    // ...
    Student student = // ...
    String city = getPropertyValue(student, "address.city");
    // ...
}

@SuppressWarnings("unchecked")
public static <T> T getPropertyValue(Object obj, String string) {
    Object ret = obj;
    String[] parts = string.split("\\.");

    for(String field : parts) {
        try {
            Class<?> clazz = ret.getClass();
            Field f = clazz.getDeclaredField(field);
            f.setAccessible(true);
            ret = f.get(ret);
        } catch(NoSuchFieldException | SecurityException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    return (T) ret;
}

制作#getPropertyValue方法static,以便您可以随时随地引用它,甚至可以import静态引用它。

答案 2 :(得分:2)

默认情况下,Java不支持此语法。但你可以轻松自己做 首先解析要访问属性的String

 String[] path = "a.b.x".split("\\.");

注意:您需要转义.字符,因为String#split适用于Regular Expressions,而.被视为RegEx中的特殊通配符。

之后,您可以使用path中的部分来查找如下值:

Object o = ... // An Object to start with, "Student" in your 
               // example (don't make it Student o = ... though!)
for(String part : path){
    o = resolveField(o, part) // Overwrites with the new object
}

最终结果保存在o

所有反射都发生在方法resolveField

Object resolveField(Object root, String fieldName) throws NoSuchFieldException, IllegalAccessException {
    Class<?> clazz = root.getClass();
    Field field = clazz.getDeclaredField(fieldName);
    field.setAccessible(true); // Lets you work with private fields. You do not 
                               // have to restore the old value as it's only 
                               // for the Field object, not for the field itself
    return field.get(root);
}

请注意,有些库已经包含此功能,例如Java Expressions Library,虽然远不止于此。

答案 3 :(得分:-1)

是的,请填写您的字段/属性public,例如

public class Student {
    public Address address;

}

public class Address {
    public String town;
    public String street;
    public String city;

}

并摆脱你的getter / setter