使用Java反射调用变量arity方法?

时间:2012-02-27 19:58:31

标签: java reflection variadic-functions arity

我想了解使用Java反射调用变量arity方法可能会发生什么。假设我们有一个简单的方法:

void doAllTheThings(Object ... things) {
  // ...which does something with all the things...
}

我们想要动态调用它,所以我们通过反射来获取方法:

Method doItAll = Superklass.getDeclaredMethod("doAllTheThings", Object[].class);

并传入一个数组:

Object[] allTheThings = new Object[] { "abc", true, 15 };
doItAll.invoke(allTheThings);

现在,这似乎不像我的直觉所说的那样有效;特别是,当我尝试使用像这样的varargs调用方法时,我似乎得到了IllegalArgumentException的各种阴影。

显然我在这里缺少一些东西。我的猜测是,这与变量如何被编组到varargs中有关。我找到了this four year old blog post which seems to be talking about the same issue,但我无法重现那里的“成功”案例。关于这里可能会发生什么的任何想法?

1 个答案:

答案 0 :(得分:8)

在这种情况下你需要传递Object[][]

Object[] allTheThings = new Object[] { "abc", true, 15 };
doItAll.invoke(o, new Object[]{allTheThings});

原因是编译器将单个things参数转换为Object[]类型的单个参数,invoke采用带参数值的数组。

考虑一个包含更多参数的方法,以使其更清晰:

void doMoreThings(Foo bar, Object ... things) { ... }

Object[] allTheThings = new Object[] { "abc", true, 15 };
doMore.invoke(o, new Object[]{new Foo(), allTheThings});

invoke本身被声明为采用varargs,因此您可以让编译器为您创建外部数组。但如果你传递Object[],它就不会这样做,因为它认为你已经这样做了。所以只需从编译器中隐藏这个事实:

doItAll.invoke(o, (Object)allTheThings);
doMore.invoke(o, new Foo(), allTheThings);

注意第一行中的强制转换,现在编译器现在不再存在已经存在的数组,因此它创建了一个数组。在第二行中,这不是必需的,因为编译器无论如何都没有其他机会。

修改: 请注意,您的代码甚至无法编译,因为您错过了使用doAllTheThings方法将类的实例传递给invoke(我在代码中将其命名为o。)