gpt4 book ai didi

java - 如何使用可变参数调用 MethodHandle

转载 作者:搜寻专家 更新时间:2023-10-31 19:51:59 27 4
gpt4 key购买 nike

我正在尝试用 MethodHandle 替换反射调用,但可变参数似乎无法处理。

我的反射调用器目前看起来像这样:

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 公开的接口(interface)必须保持不变):

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

这在大多数情况下都很好用。但是 varargs 破坏了一切。例如。有一个像这样的方法:

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所有测试案例中的表现要差得多。

最佳答案

似乎您只需要调用一次 .asFixedArity,因为默认情况下 java 将使用 asVarargsCollector 创建方法句柄

public class Main {
public static String test(int i, String... args) { return "works!"; }

public static void main(String[] args) throws Throwable {
Method method = Main.class.getMethod("test", int.class, String[].class);
System.out.println(new Invoker(method).execute(null, new Object[]{1, new String[] {"foo", "bar"} }));
}

public static class Invoker {
private final MethodHandle handle;

public Invoker(final Method delegate) throws Exception {
MethodHandle handle = MethodHandles.lookup().unreflect(delegate);
if (Modifier.isStatic(delegate.getModifiers())) { // for easy static methods support
handle = MethodHandles.dropArguments(handle, 0, Object.class);
}
this.handle = handle.asFixedArity();
}

public Object execute(Object target, Object[] args) throws Throwable {
Object[] allArgs = new Object[args.length + 1];
allArgs[0] = target;
System.arraycopy(args, 0, allArgs, 1, args.length);
return handle.invokeWithArguments(allArgs);
}
}
}

还有许多其他可能的解决方案,比如您可以向 Invoker 构造函数添加更多逻辑(静态工厂可能是个好主意)并使用 asType 方法来准备您想要的签名,然后您应该能够使用 .invokeExact 调用它以获得小的性能提升。

你也可以继续使用 Method ;)

关于java - 如何使用可变参数调用 MethodHandle,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52093694/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com