首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用varargs调用MethodHandle

如何使用varargs调用MethodHandle
EN

Stack Overflow用户
提问于 2018-08-30 09:32:48
回答 2查看 535关注 0票数 6

我试图用MethodHandle替换反射调用,但是varargs似乎是不可能处理的。

我的反射调用程序目前看起来如下:

代码语言:javascript
复制
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公开的接口必须保持不变):

代码语言:javascript
复制
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);
    }
}

在大多数情况下,这是很好的。但是瓦拉格破坏了一切。有一种方法,如:

代码语言:javascript
复制
public String test(int i, String... args) {
    return ...;
}

他们的论点如下:

代码语言:javascript
复制
Object[] args = new Object[] {10, new String[] {"aaa", "bbb"}};

而上面实现的execute将失败。我尝试了各种组合的asSpreader()MethodHandles.explicitCastArguments()invoke,而不是invokeWithArguments等,但没有成功。

调用varargs方法的唯一方法是内联地提供参数,而不是作为数组。例如。

代码语言:javascript
复制
handle.invokeWithArguments(10, "aaa", "bbb")

但是,我不能这样做,不能保持Invoker目前所具有的泛型性质。

这真的不可能像我努力的那样做吗?

更新:在对各种场景进行基准测试之后,我决定坚持反射,因为invokeWithArguments在所有测试案例中的表现都要糟糕得多。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-08-30 16:07:21

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

代码语言:javascript
复制
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);
        }
    }
}

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

你也可以继续使用Method ;)

票数 6
EN

Stack Overflow用户

发布于 2018-08-30 11:59:06

我完成了您的代码来重现您的问题,但它使用invokeWithArguments工作。也许我漏掉了什么?

代码语言:javascript
复制
public class Main {

    public String test(int i, String... args) {
        return i + Stream.of(args).collect(Collectors.joining());
    }


    public static void main(String[] args) throws Throwable {
        Main main = new Main();
        Method method = Main.class.getMethod(
            "test",
            int.class,
            String[].class)
        Invoker invoker = new Invoker(method);
        assertEquals("1foobar", invoker.execute(main, new Object[]{1, "foo", "bar"})); // Success
    }


    public static class Invoker {

        private final MethodHandle handle;

        public Invoker(final Method delegate) throws Exception {
            this.handle = MethodHandles.lookup().unreflect(delegate);
        }

        public Object execute(Object target, Object[] args) throws Throwable {
            // Add the target and all arguments in a new array
            Object[] allArgs = Stream.concat(Stream.of(new Object[]{target}), Stream.of(args))
                .toArray(Object[]::new);
            return handle.invokeWithArguments(allArgs);
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52093694

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档