【发布时间】:2019-02-05 04:50:47
【问题描述】:
我正在尝试用 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 而不是invokeWithArguments 等的各种组合,但没有成功。
我可以调用可变参数方法的唯一方法是提供内联参数而不是数组。例如
handle.invokeWithArguments(10, "aaa", "bbb")
但我不能这样做并保持它当前拥有的Invoker 的通用性质。
这真的不可能按照我尝试的方式进行吗?
更新:
在对各种场景进行基准测试后,我决定坚持使用反射,因为invokeWithArguments 在所有测试用例中的表现要差得多。
【问题讨论】:
-
你试过用数组代替可变参数的invokeExact吗?
-
@GotoFinal 废话,我没有,它有效!但是......我确实需要自动装箱才能继续工作...... Aaargh。
-
请注意,您可以简单地使用
return handle.bindTo(target).invokeWithArguments(args);,而不是Object[] allArgs = Stream.concat(Stream.of(target), Stream.of(args)).toArray(Object[]::new); return handle.invokeWithArguments(allArgs);
标签: java reflection java-7 variadic-functions methodhandle