在Java中是否可能动态地设置对象属性(不使用反射)?

3

假设我有以下类:

class Foo
{
   public String bar;
   public String baz;
}

我有以下代码,在另一个类中:

Foo foo = new Foo();
String[] properties = {"bar", "baz"};
String[] values = {"barValue", "bazValue"};

是否可以遍历属性数组,并使用它来设置Foo的值?例如:

for (int i = 0; i < properties.length; i++)
{
  foo[ properties[i] ] = values[i];
}

类似上述情况是否可能发生?

1
但为什么要有“无反射”限制呢? - anubhava
1
只需使用 HashMap - roippi
我相信Roippi的解决方案是唯一的选择,根据你所描述的情况,除非你想编写一个自定义函数来接受两个参数,并测试属性以将它们分配给正确的变量。 - Nathan Merrill
我的例子很简单,显然我的类会有其他方法,否则我会使用HashMap。 - Ali
@roippi 反射被认为对性能有负面影响。 - Ali
显示剩余2条评论
2个回答

6
类似上述内容的东西是可能的吗?
不可能。
根据你定义的属性,你只有两个选择:
1. 编写或生成Java代码(或字节码)来引用foo.barfoo.baz字段 2. 使用反射
如果你想要动态属性,使用一个Map对象;例如HashMap<String, String>
对于你的举例说明,它不能工作因为:
1. 普通对象字段不能像数组一样被索引 2. 与C++、Python和其他语言不同,Java不支持核心语言构造的任何特定重载(除了方法)
Java不是一种支持此类操作的动态语言。你需要学会如何与它所提供的共存......或者使用另一种编程语言。
你这样评论:
“反射被认为影响性能。”
嗯,是这样,但它是相对的。通过反射访问或更新字段比使用普通Java代码访问/更新它们要慢10到100倍。然而,如果你只偶尔这样做,性能开销可能并不相关。如果它确实成为问题,那么你的选项包括手写或生成代码。例如:
public class Foo
{
   public String bar;
   public String baz;

   public void setNamedProperty(String name, String value) {
       switch (name) {
       case "bar": 
           bar = value;
           break;
       case "baz": 
           baz = value;
           break;
       default:
           throw new IllegalArgumentException("Unknown property name");
       }
   }
}

仅供参考,这段代码的时间效率与在支持动态属性的语言中设置动态属性相当。 (我猜测它会更加节省空间,因为通常使用本地编码哈希表实现动态属性。)


我不明白"编写或生成Java代码(或字节码)以引用foo.bar字段"的意思?能否请您详细说明一下... - Kanagavelu Sugumar
@KanagaveluSugumar - 举个例子,"编写一个setter方法并调用它"。请注意,这些是动态属性的替代方案 - Stephen C

1

当你面对Java Beans时,可以使用内省(Introspection),这是一种更好的方法。

缺点包括:

  • 如果属性存在getter/setter,则将调用它们,否则将直接访问字段。
  • 你可以迭代属性,因为它会给你一个PropertyDescriptor的数组。
  • 它支持BeanInfo类,因此你可以配置bean属性、定义不同命名约定的访问器/变量等。
  • 你可以使用像Apache Commons BeanUtils或者Spring BeanWrapper API之类的库。

有关更多信息,请参阅java.beans.Introspector javadocs。

顺便提一下,据我所知,内省是基于反射构建的,因此它本身也使用了反射。


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