MethodHandle 接受 Array 对象参数的 MethodType 转换
MethodType transformation for MethodHandle to accept Array Object paramters
我想将 String.startsWith
从 (String, String)boolean
调整为 (String[])boolean
,以便它可以接受 String[]
参数,其中前两个参数将映射到 (String, String)
。因此,我写了下面的示例代码:
MethodHandle test =MethodHandles.publicLookup().findVirtual(String.class, "startsWith", MethodType.methodType(boolean.class, String.class));
String[] myArgs = {"result", "data", "sijie"};
MethodHandle adapt = test.asSpreader(String[].class, 2);
System.out.println("Adapt... "+ adapt.type().toString());
System.out.println("Compare Result: "+ adapt.invokeExact(myArgs)); //Expect to return false.
MethodHandle
到String.startsWith
首先适配boolean (String[])
。但结果显示 adapt.invokeExact
失败。
Adapt... (String[])boolean
Exception in thread "main" java.lang.invoke.WrongMethodTypeException: expected (String[])boolean but found (String[])Object
at java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:349)
at java.lang.invoke.Invokers.checkExactType(Invokers.java:360)
at org.bytecode.generation.sample.App.main(App.java:78)
堆栈跟踪中的新 (String[])
对象非常混乱。谁能就如何修复它提供一些建议?
谢谢
这个问题可以抽象为:
如何调整只接受 (String, String)boolean
的 Methodhandle
以便它可以接受 (String[])boolean
参数?
多次重试后得到解决方案。
MethodHandle guard =MethodHandles.publicLookup().findVirtual(String.class, "startsWith", MethodType.methodType(boolean.class, String.class));
String[] myArgs = {"result", "data", "sijie"};
guard.invokeWithArguments(Arrays.copyOfRange(myArgs, 0, guard.type().parameterCount()));
问题出在 invokeExact
调用上——因为 invokeExact
是签名多态的,您需要使用强制转换显式指定 return 类型:
System.out.println("Compare Result: "+ (boolean)adapt.invokeExact(myArgs));
这就是堆栈跟踪试图通过 expected (String[])boolean but found (String[])Object
告诉您的内容——因为您没有强制转换为 boolean
,javac
假定方法句柄具有类型(String[])Object
,但在运行时,它的类型是 (String[])boolean
。 (顺序可能会令人困惑。可以把它想象成 "given the method handle, what type do I expect to have been recorded at compile time for invokeExact
?")
另请参阅我对 Why can't I .invokeExact() here, even though the MethodType is OK? 的回答。 (该问题涉及子类型化和解决方案 asType
以及添加强制转换,但信息相似。)
我想将 String.startsWith
从 (String, String)boolean
调整为 (String[])boolean
,以便它可以接受 String[]
参数,其中前两个参数将映射到 (String, String)
。因此,我写了下面的示例代码:
MethodHandle test =MethodHandles.publicLookup().findVirtual(String.class, "startsWith", MethodType.methodType(boolean.class, String.class));
String[] myArgs = {"result", "data", "sijie"};
MethodHandle adapt = test.asSpreader(String[].class, 2);
System.out.println("Adapt... "+ adapt.type().toString());
System.out.println("Compare Result: "+ adapt.invokeExact(myArgs)); //Expect to return false.
MethodHandle
到String.startsWith
首先适配boolean (String[])
。但结果显示 adapt.invokeExact
失败。
Adapt... (String[])boolean
Exception in thread "main" java.lang.invoke.WrongMethodTypeException: expected (String[])boolean but found (String[])Object
at java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:349)
at java.lang.invoke.Invokers.checkExactType(Invokers.java:360)
at org.bytecode.generation.sample.App.main(App.java:78)
堆栈跟踪中的新 (String[])
对象非常混乱。谁能就如何修复它提供一些建议?
谢谢
这个问题可以抽象为:
如何调整只接受 (String, String)boolean
的 Methodhandle
以便它可以接受 (String[])boolean
参数?
多次重试后得到解决方案。
MethodHandle guard =MethodHandles.publicLookup().findVirtual(String.class, "startsWith", MethodType.methodType(boolean.class, String.class));
String[] myArgs = {"result", "data", "sijie"};
guard.invokeWithArguments(Arrays.copyOfRange(myArgs, 0, guard.type().parameterCount()));
问题出在 invokeExact
调用上——因为 invokeExact
是签名多态的,您需要使用强制转换显式指定 return 类型:
System.out.println("Compare Result: "+ (boolean)adapt.invokeExact(myArgs));
这就是堆栈跟踪试图通过 expected (String[])boolean but found (String[])Object
告诉您的内容——因为您没有强制转换为 boolean
,javac
假定方法句柄具有类型(String[])Object
,但在运行时,它的类型是 (String[])boolean
。 (顺序可能会令人困惑。可以把它想象成 "given the method handle, what type do I expect to have been recorded at compile time for invokeExact
?")
另请参阅我对 Why can't I .invokeExact() here, even though the MethodType is OK? 的回答。 (该问题涉及子类型化和解决方案 asType
以及添加强制转换,但信息相似。)