1

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

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);

现在,这似乎不像我的直觉所想的那样起作用。IllegalArgumentException特别是,当我尝试使用这样的可变参数调用方法时,我似乎得到了各种各样的阴影。

很明显,我在这里缺少一些东西。我的猜测是这在某种程度上与变量如何编组到可变参数中有关。我发现这篇已有四年历史的博客文章似乎在谈论同样的问题,但无法重现那里的“成功”案例。对这里可能发生的事情有任何想法吗?

4

1 回答 1

9

在这种情况下,您需要传入一个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本身声明为采用可变参数,因此您可以让编译器为您创建外部数组。但是如果你通过了它就不会这样做Object[],因为它认为你已经这样做了。所以只需对编译器隐藏这个事实:

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

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

编辑:请注意,您的代码甚至没有编译,因为您错过了使用doAllTheThings方法传递类的实例(我在我的代码中invoke命名它)。o

于 2012-02-27T20:02:27.887 回答