How to find the constructor of a MethodHandle array with MethodHandles.Lookup?

How do I get a MethodHandle for an array constructor of type int[]::new ?

This does not work:

 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()); } 

The result is the following:

 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 

And it does not:

 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()); } 

It seems that instead of the constructor, instead of Object , <

:

 MethodHandle()Object java.lang.Object@36baf30c 
+5
source share
2 answers

As I know, int[].class does not have a constructor, so it is not accessible through reflection at least.

Instead, you can try to get a MethodHandle in an Array factory method:

 MethodHandle mh = lookup.findStatic(Array.class, "newInstance", MethodType.methodType(Object.class, Class.class, int.class)); 

and create an array by calling it.

+4
source

It seems that @MaximSIvanov is right: there is no built-in way to get such a method handle. However, nothing prevents you from creating a special method for this purpose and providing a handle to this method:

 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] } } 

Something similar is actually performed by the java compiler when compiling the int[]::new method reference: a private private method is created. You can verify by compiling the following class:

 import java.util.function.*; public class Test { IntFunction<int[]> fn = int[]::new; } 

By running javap -p -c Test , you will see that the helper private method is generated and associated as MethodHandle with invokedynamic :

 private static java.lang.Object lambda$MR$new$new$4ffde7b3$1(int); Code: 0: iload_0 1: newarray int 3: areturn 
+1
source

Source: https://habr.com/ru/post/1245280/


All Articles