如何在Java中动态读取对象属性?

14

有没有办法以动态方式读取和打印对象属性(Java)?例如,如果我有以下对象:

public class A{
  int age ;
  String name;
  float income;

}

public class B{
 int age;
 String name;
}

public class mainA{
   A obj1 = new A();
   method(A);
   method(B); 
}

the output should be like

While running method(A):
Attribute of Object are age,name,income;
While executing method(B):
Attribute of Objects are age,name;

我的问题是,我可以在method()中传递各种对象,是否有一种通用的方法来访问不同对象的属性。


2
如果可以避免,不要这样做,因为它会使调试变得非常痛苦。Java 的一个好处是默认情况下非常不神秘。如果你能够以一种非常可读和易于调试的方式完成而不是使用魔法或反射,那么从长远来看你会更加受益。 - rid
5个回答

21
你想要使用反射API。具体来说,请查看查找类成员

你可以按如下方式进行操作:

public void showFields(Object o) {
   Class<?> clazz = o.getClass();

   for(Field field : clazz.getDeclaredFields()) {
       //you can also use .toGenericString() instead of .getName(). This will
       //give you the type information as well.

       System.out.println(field.getName());
   }
}

我只想提醒一下,通常情况下你不需要像这样做任何事情,并且对于大多数情况,你可能不应该这样做。反射可能会使代码难以维护和阅读。当然,在某些特定情况下,您需要使用反射,但这些情况相对较少。


1
@Chris,感谢您的编辑,我忘记了;我知道那里必须有一个<?> - Vivin Paliath
有没有办法同时获取字段值? - Panadol Chong

9
使用org.apache.commons.beanutils.PropertyUtils,我们可以做到这一点。如果为bean定义了适当的getter和setter,我们也可以动态设置值。
import org.apache.commons.beanutils.PropertyUtils;
import java.beans.PropertyDescriptor;

public class PropertyDescriptorTest {

    public static void main(String[] args) {

        // Declaring and setting values on the object
        AnyObject anObject = new AnyObject();
        anObject.setIntProperty(1);
        anObject.setLongProperty(234L);
        anObject.setStrProperty("string value");

        // Getting the PropertyDescriptors for the object
        PropertyDescriptor[] objDescriptors = PropertyUtils.getPropertyDescriptors(anObject);

        // Iterating through each of the PropertyDescriptors
        for (PropertyDescriptor objDescriptor : objDescriptors) {
            try {
                String propertyName = objDescriptor.getName();
                Object propType = PropertyUtils.getPropertyType(anObject, propertyName);
                Object propValue = PropertyUtils.getProperty(anObject, propertyName);

                // Printing the details
                System.out.println("Property="+propertyName+", Type="+propType+", Value="+propValue);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

}

设置特定属性的值:

// Here we have to make sure the value is
// of the same type as propertyName
PropertyUtils.setProperty(anObject, propertyName, value);

输出结果如下:
Property=class, Type=class java.lang.Class, Value=class genericTester.AnyObject
Property=intProperty, Type=int, Value=1
Property=longProperty, Type=class java.lang.Long, Value=234
Property=strProperty, Type=class java.lang.String, Value=string value

org.apache.commons.beanutils.PropertyUtils存在漏洞。是否有更好的解决方案?https://nvd.nist.gov/vuln/detail/CVE-2019-10086 - mokarakaya

2
您可以使用反射来获取对象中的每个字段(如果安全配置允许的话)。
如果您不是出于自我教育的目的而需要它,那么使用Apache Commons中的ReflectionUtils可能是值得的。

1

你可以使用反射,但API不太好用。但是你正在尝试的事情根本不是面向对象的。A和B应该有一个“打印自己”的方法,它将输出它们的值(你应该在超类/接口中指定该方法,以便使用多态调用该方法)。


谢谢回复,上面的代码只是我问题的简化版本。我有相同情况需要使用反射 API。 - Mike

1

我认为我会考虑不同的方法。

如果你真的想把它们当作数据来处理,它们不能是哈希表吗?(它们有关联代码吗?)

反射可以做到这一点,但这是最后的手段——在降低到反射之前,你应该认真考虑不同的方法。

必须访问变量的情况存在——比如数据库映射(Hibernate)和注入(Spring)。你可能要考虑是否需要一个打包的解决方案来满足你的需求,这样未来的程序员就可以理解你所做的事情,而不必学习你特定解决方案的所有内容。

此外,Spring注入可以做一些可能符合你的需求的事情。

还有,如果你要使用反射,请认真考虑注释,这样你就不会将功能绑定到应该是简单任意属性名称的东西上。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接