如何使用 MethodHandles.Lookup 查找数组构造函数 MethodHandle?
How do I lookup an array constructor MethodHandle with MethodHandles.Lookup?
如何为像 int[]::new
这样的数组构造函数获取 MethodHandle
?
这行不通:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class, int.class));
System.out.println(mh);
System.out.println(mh.invoke());
}
结果是:
Exception in thread "main" java.lang.NoSuchMethodException: no such constructor: [I.<init>(int)void/newInvokeSpecial
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:871)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1382)
at java.lang.invoke.MethodHandles$Lookup.findConstructor(MethodHandles.java:920)
at xx.main(xx.java:11)
Caused by: java.lang.NoSuchMethodError: java.lang.Object.<init>(I)V
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:987)
... 3 more
这也不行:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class));
System.out.println(mh);
System.out.println(mh.invoke());
}
似乎找到了 Object
的构造函数,而不是:
MethodHandle()Object
java.lang.Object@36baf30c
据我所知int[].class
没有构造函数,所以它至少不能通过反射获得。
相反,您可以尝试在 Array 的工厂方法上获取 MethodHandle
:
MethodHandle mh = lookup.findStatic(Array.class, "newInstance",
MethodType.methodType(Object.class, Class.class, int.class));
并通过调用创建一个数组。
@MaximSIvanov 似乎是对的:没有内置方法来获取此类方法句柄。然而,没有什么能阻止您为此目的创建一个特殊方法并提供该方法的句柄:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
public class ArrayMethodHandles {
private static int[] makeIntArray(int size) {
return new int[size];
}
public static MethodHandle createIntArray() {
try {
return MethodHandles.lookup().findStatic(ArrayMethodHandles.class,
"makeIntArray", MethodType.methodType(int[].class, int.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new InternalError();
}
}
public static void main(String[] args) throws Throwable {
MethodHandle mh = createIntArray();
int[] array = (int[])mh.invokeExact(10);
System.out.println(Arrays.toString(array));
// prints [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
}
当您编译 int[]::new
方法引用时,java 编译器实际上会执行类似的操作:创建辅助私有方法。您可以通过编译以下内容来检查 class:
import java.util.function.*;
public class Test {
IntFunction<int[]> fn = int[]::new;
}
运行 javap -p -c Test
您将看到辅助私有方法已生成并作为 MethodHandle 链接到 invokedynamic
:
private static java.lang.Object lambda$MR$new$newffde7b3(int);
Code:
0: iload_0
1: newarray int
3: areturn
如何为像 int[]::new
这样的数组构造函数获取 MethodHandle
?
这行不通:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class, int.class));
System.out.println(mh);
System.out.println(mh.invoke());
}
结果是:
Exception in thread "main" java.lang.NoSuchMethodException: no such constructor: [I.<init>(int)void/newInvokeSpecial
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:871)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1382)
at java.lang.invoke.MethodHandles$Lookup.findConstructor(MethodHandles.java:920)
at xx.main(xx.java:11)
Caused by: java.lang.NoSuchMethodError: java.lang.Object.<init>(I)V
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:987)
... 3 more
这也不行:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class));
System.out.println(mh);
System.out.println(mh.invoke());
}
似乎找到了 Object
的构造函数,而不是:
MethodHandle()Object
java.lang.Object@36baf30c
据我所知int[].class
没有构造函数,所以它至少不能通过反射获得。
相反,您可以尝试在 Array 的工厂方法上获取 MethodHandle
:
MethodHandle mh = lookup.findStatic(Array.class, "newInstance",
MethodType.methodType(Object.class, Class.class, int.class));
并通过调用创建一个数组。
@MaximSIvanov 似乎是对的:没有内置方法来获取此类方法句柄。然而,没有什么能阻止您为此目的创建一个特殊方法并提供该方法的句柄:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
public class ArrayMethodHandles {
private static int[] makeIntArray(int size) {
return new int[size];
}
public static MethodHandle createIntArray() {
try {
return MethodHandles.lookup().findStatic(ArrayMethodHandles.class,
"makeIntArray", MethodType.methodType(int[].class, int.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new InternalError();
}
}
public static void main(String[] args) throws Throwable {
MethodHandle mh = createIntArray();
int[] array = (int[])mh.invokeExact(10);
System.out.println(Arrays.toString(array));
// prints [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
}
当您编译 int[]::new
方法引用时,java 编译器实际上会执行类似的操作:创建辅助私有方法。您可以通过编译以下内容来检查 class:
import java.util.function.*;
public class Test {
IntFunction<int[]> fn = int[]::new;
}
运行 javap -p -c Test
您将看到辅助私有方法已生成并作为 MethodHandle 链接到 invokedynamic
:
private static java.lang.Object lambda$MR$new$newffde7b3(int);
Code:
0: iload_0
1: newarray int
3: areturn