微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

MethodHandle 强制转换返回类型

如何解决MethodHandle 强制转换返回类型

我尝试通过方法句柄将方法链接在一起,其中一些来自泛型类型。如果函数返回泛型类型,我必须为 MethodType 指定 Object.class,但我认为没有简单的方法可以将其转换回泛型类型参数类型。在大多数情况下,这没有问题,因为 invoke 似乎会自动转换它们,但我必须创建可以使用 invokeExact 运行的 mhs。有没有简单的方法可以使用方法句柄进行转换?

我的测试代码

public static void main(String[] args) throws Throwable {
    class Prefixer {
        public static String prefix(String s) {
            return "Number: " + s;
        }
    }
    IntFunction<String> converter = Integer::toString;

    var lookup = MethodHandles.lookup();
    var prefixMH = lookup.findStatic(Prefixer.class,"prefix",MethodType.methodType(String.class,String.class));

    var converterMH = lookup.findVirtual(IntFunction.class,"apply",MethodType.methodType(Object.class,int.class));
    converterMH = converterMH.bindTo(converter);

    /* Doesn't work because converter is a (int)Object and no (int)String
    var mh = MethodHandles.filterarguments(prefixMH,converterMH);
     */

    /* Does work for invoke but not for invokeExact
    var prefixCasted = MethodHandles.explicitCastArguments(prefixMH,Object.class));
    var mh = MethodHandles.filterarguments(prefixCasted,converterMH);
    */
    /* Does work for invoke but not for invokeExact */
    var mh = MethodHandles.filterarguments(prefixMH,converterMH.asType(MethodType.methodType(String.class,int.class)));

    System.out.println(mh.invoke(12));
    System.out.println(mh.invokeExact(42));
}

解决方法

您当前的代码对我来说看起来不错,您只需要在调用站点使用强制转换即可:

System.out.println((String) mh.invokeExact(42));

否则调用站点的类型将为 (int)Object,它与 MethodHandle (int)String 的类型不匹配,并且您会得到 WMTE。

您的通话的 invoke 版本:

System.out.println(mh.invoke(12));

将使用 mh 调用将 (int)Object 的类型隐式转换为 asType(调用站点的类型),然后调用生成的方法句柄。

如果你想明确地这样做并使用 invokeExact 你可以这样做:

mh = mh.asType(MethodType.methodType(Object.class,int.class));
System.out.println(mh.invokeExact(42));

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。