在Java上动态调用方法

时间:2016-04-30 14:34:22

标签: java method-invocation

在工作中,我们必须为我们的客户生成一个报告,该报告在一周内多次更改其参数。 此报告是从我们数据库中的单个表生成的。 例如,假设一个包含100列的表,我今天必须生成一个只有5列的报告,但明天我必须使用95列生成。 考虑到这一点,我创建了一个包含指定表的所有列的TO类,我的查询返回所有列(SELECT * FROM TABLE)。

我尝试创建的是生成报告的动态表单。 我首先考虑创建一个简单的框架,列出列为复选框的列,用户可以选择他想要的列(当然有一个按钮选择全部,另一个按钮取消全选)。

由于所有列都与TO类的属性同名,因此我开发了以下代码(我有Google这个):

Class c = Test.class;

for(int i = 0; i < listOfAttributes.length; i++)
{
    auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}

这是做我需要的更好的方法吗?

提前致谢。

Obs。:TO类的getter具有模式&#34; getAttribute_Name&#34;。

注意:此问题与用户询问如何在给定特定名称的情况下调用某个方法的问题不同。我知道该怎么做。我要问的是,这是否是解决我所描述问题的更好方法。

2 个答案:

答案 0 :(得分:0)

我的Java有点受限制,但我相信这与您使用反射一样好。

Class<?> c = Test.class;

for (String attribute : listOfAttributes) {
    auxText += String.valueOf(c.getMethod("get" + attribute).invoke(this, null));
}

但是,由于这听起来像来自可能不受信任的数据,我建议在这种情况下使用HashMap,并明确引用每个方法。首先,它明确说明了可以动态调用哪些方法。其次,它更安全,编译时错误比运行时错误更好。第三,它可能更快,因为它完全避免反射。对此产生影响:

private static final HashMap<String, Supplier<Object>> methods = new HashMap<>();

// Initialize all the methods.
static {
    methods.set("Foo", Test::getFoo);
    methods.set("Bar", Test::getBar);
    // etc.
}

private String invokeGetter(String name) {
    if (methods.containsKey(name)) {
        return String.valueOf(methods.get(name).get());
    } else {
        throw new NoSuchMethodException();
    }
}

这可能听起来像是一次严重的DRY违规行为,但重复至少可以确保你不会意外地被无关的吸气者召唤。

答案 1 :(得分:0)

Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
    auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}

你可以通过Java Bean,IntrospectorPropertyDescriptor稍微优雅地做到这一点,但它有点啰嗦:

Map<String, Method> methods = new HashMap<>();
Class c = this.getClass(); // surely?
for (PropertyDescriptor pd : Introspector.getBeanInfo(c).getPropertyDescriptors())
{
    map.put(pd.getName(), pd.getReadMethod();
}
// 
for (int i = 0; i < listOfAttributes.length; i++)
{
    Method m = methods.get(listOfAttributes[i]);
    if (m == null)
        continue;
    auxText += String.valueOf(m.invoke(this, null));
}