MethodHandle 强制转换 return 类型
MethodHandle cast return type
我尝试 link 通过方法句柄将方法组合在一起,其中一些来自泛型类型。如果函数 returns 是泛型类型,我必须为 MethodType 指定 Object.class,但我认为没有简单的方法可以将它转换回泛型参数类型。在大多数情况下,这没有问题,因为 invoke 似乎会自动转换它们,但我必须创建 mhs,它可以是 运行 with invokeExact。没有简单的方法来使用 methodhandles 进行转换吗?
我的测试代码:
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, 0, converterMH);
*/
/* Does work for invoke but not for invokeExact
var prefixCasted = MethodHandles.explicitCastArguments(prefixMH, MethodType.methodType(String.class, Object.class));
var mh = MethodHandles.filterArguments(prefixCasted, 0, converterMH);
*/
/* Does work for invoke but not for invokeExact */
var mh = MethodHandles.filterArguments(prefixMH, 0, 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));
将使用 asType
调用将 mh
的类型隐式转换为 (int)Object
(调用站点的类型),然后调用生成的方法句柄。
如果你想明确地这样做并使用 invokeExact
你可以这样做:
mh = mh.asType(MethodType.methodType(Object.class, int.class));
System.out.println(mh.invokeExact(42));
我尝试 link 通过方法句柄将方法组合在一起,其中一些来自泛型类型。如果函数 returns 是泛型类型,我必须为 MethodType 指定 Object.class,但我认为没有简单的方法可以将它转换回泛型参数类型。在大多数情况下,这没有问题,因为 invoke 似乎会自动转换它们,但我必须创建 mhs,它可以是 运行 with invokeExact。没有简单的方法来使用 methodhandles 进行转换吗?
我的测试代码:
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, 0, converterMH);
*/
/* Does work for invoke but not for invokeExact
var prefixCasted = MethodHandles.explicitCastArguments(prefixMH, MethodType.methodType(String.class, Object.class));
var mh = MethodHandles.filterArguments(prefixCasted, 0, converterMH);
*/
/* Does work for invoke but not for invokeExact */
var mh = MethodHandles.filterArguments(prefixMH, 0, 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));
将使用 asType
调用将 mh
的类型隐式转换为 (int)Object
(调用站点的类型),然后调用生成的方法句柄。
如果你想明确地这样做并使用 invokeExact
你可以这样做:
mh = mh.asType(MethodType.methodType(Object.class, int.class));
System.out.println(mh.invokeExact(42));