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

Jos*_*man 1 java reflection variadic-functions arity

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

void doAllTheThings(Object ... things) {
  // ...which does something with all the things...
}
Run Code Online (Sandbox Code Playgroud)

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

Method doItAll = Superklass.getDeclaredMethod("doAllTheThings", Object[].class);
Run Code Online (Sandbox Code Playgroud)

并传入一个数组:

Object[] allTheThings = new Object[] { "abc", true, 15 };
doItAll.invoke(allTheThings);
Run Code Online (Sandbox Code Playgroud)

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

显然我在这里缺少一些东西.我的猜测是,这与变量如何被编组到varargs中有关.我发现这篇四年前的博客文章似乎在谈论同样的问题,但我无法重现那里的"成功"案例.关于这里可能会发生什么的任何想法?

Phi*_*ler 8

Object[][]在这种情况下你需要传入一个:

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

原因是things编译器将单个参数转换为单个参数类型Object[],并invoke使用参数值获取数组.

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

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

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

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

doItAll.invoke(o, (Object)allTheThings);
doMore.invoke(o, new Foo(), allTheThings);
Run Code Online (Sandbox Code Playgroud)

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

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