我正在尝试用 MethodHandle 替换反射调用,但 varargs 似乎无法处理。
我的反射调用程序目前看起来像这样:
public class Invoker {
private final Method delegate;
public Invoker(Method delegate) {
this.delegate = delegate;
}
public Object execute(Object target, Object[] args) {
return delegate.invoke(target, args);
}
}
我目前重写它的尝试看起来像这样(Invoker
暴露的接口必须保持不变):
public class Invoker {
private final Method delegate;
private final MethodHandle handle;
public Invoker(Method delegate) {
this.delegate = delegate;
this.handle = MethodHandles.lookup().unreflect(delegate);
}
public Object execute(Object target, Object[] args) throws InvocationTargetException, IllegalAccessException {
Object[] allArgs = Stream.concat(Stream.of(target), Stream.of(args)).toArray(Object[]::new);
return handle.invokeWithArguments(allArgs);
}
}
这在大多数情况下都很好用。但是可变参数打破了一切。例如有一个方法,如:
public String test(int i, String... args) {
return ...;
}
和这样的论点:
Object[] args = new Object[] {10, new String[] {"aaa", "bbb"}};
并且execute
如上所述实施将失败。asSpreader()
我尝试了, MethodHandles.explicitCastArguments()
,invoke
而不是etc的各种组合,invokeWithArguments
但没有成功。
我可以调用可变参数方法的唯一方法是提供内联参数而不是数组。例如
handle.invokeWithArguments(10, "aaa", "bbb")
但我不能这样做并保持Invoker
它目前具有的通用性。
这真的不可能按照我尝试的方式进行吗?
更新:
在对各种场景进行基准测试后,我决定坚持使用反射,因为在所有测试用例invokeWithArguments
中的表现都要差得多。