Java反射Beans属性API

29

有没有一种标准的方式来访问Java Bean属性,例如

class A {
   private String name;

   public void setName(String name){
       this.name = name;
   }

   public String getName(){
       return this.name;
   }

}
所以我能否使用反射API访问这个Java Bean属性名称,以便当我更改属性值时,自动调用getName和setName方法来设置和获取该属性的值。
4个回答

47

你的问题非常不清楚,但如果我理解正确:

是的。 java.beans 包中有所谓的Introspector。在那里,您可以读取 bean 的属性。

BeanInfo info = Introspector.getBeanInfo(Bean.class);
PropertyDescriptor[] pds = info.getPropertyDescriptors();

您可以通过名称找到所需的PropertyDescriptor,并且可以调用getReadMethod().invoke(..)


11
我更喜欢这种方法,因为它不需要依赖。 - Cyril Sochor
这种方式的另一个优点是可以重复使用java.lang.reflect.Method,因此在不同类实例上获取/写入相同属性的值可以更快,读取属性比使用BeanUtils快约100倍,比Spring BeanWrapper快20倍。我也喜欢perdi-estaquel的答案,因为它提供了代码示例。 - Testo Testini

45
你需要的是 BeanInfo / Introspector 机制(请参见 Bozho 的答案)。但是,直接使用此方法会很麻烦,因此你可以使用其中一种提供基于属性访问的库。最著名的可能是 Apache Commons/BeanUtils(另一个是 Spring 的 BeanWrapper 抽象)。 示例代码:
A someBean = new A();

// access properties as Map
Map<String, Object> properties = BeanUtils.describe(someBean);
properties.set("name","Fred");
BeanUtils.populate(someBean, properties);

// access individual properties
String oldname = BeanUtils.getProperty(someBean,"name");
BeanUtils.setProperty(someBean,"name","Barny"); 

为什么不直接调用 someBean.setName("Fred") 呢?对于像我这样的无知者而言。 - simpatico
1
对于单个已知属性,当然可以使用 @simpatico。但是如果您想管理许多不同类型对象的许多不同属性的访问,请使用 bean 属性。 - Sean Patrick Floyd
1
谢谢。如果属性在加载的文件中设置,然后只需调用BeanUtils.populate(someBean, properties)即可购买它; 但是在实践中,我永远不会调用set("name", "Fred"),而是可以直接调用setName("Fred")(我知道你的代码只是示例)。 - simpatico
1
如果您在编译时知道有一个setName方法的类型信息,那么您应该使用它。否则,Bean内省器可以使生活更轻松,因为它可以减少很多耦合。此外,使用内省的成本实际上并不太高(除了关键的内部循环之外)。 - Donal Fellows

3

使用 java.beans.PropertyDescriptor

在您的情况下:

A a = new A();
PropertyDescriptor nameProperty = new PropertyDescriptor("name", A.class);
nameProperty.getWriteMethod().invoke(a, "potato");
System.out.println(nameProperty.getReadMethod().invoke(a));

1

我尝试过使用BeanUtils和PropertyDescriptors,因为我没有传递给我的方法的类的信息。我甚至不知道传递的属性的数据类型,所以设置值变得困难。我知道BeanUtils应该自动转换属性并设置它,但它并没有为我保存数据。最终,我不得不依赖于获取字段。这是我所做的:

Field[] fields = className.getDeclaredFields();
for (int i=0; i<fields.length ;i++)
{
  String element = fields[i].getName();
  String propertyType = fields[i].getType().getName();
  fields[i].setAccessible(true);
  if(propertyType.equalsIgnoreCase("java.lang.Integer"))
    {
      fields[i].set(mypojoObj, Integer.parseInt(parameterValue));
    }
    else
    {
      fields[i].set(mypojoObj, parameterValue);
    }
 }

我曾经使用类似的switch-case语句将所有属性类型转换为正确的类型。当从页面获取信息时,request.getParameter(paramname)总是返回字符串,因此这种转换对我很有用。如果有更好的直接数据转换选项,将非常有帮助。

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