2016-03-18 4 views
5

Как получить MethodHandle для конструктора массива, такого как int[]::new?Как мне найти конструктор массива MethodHandle с MethodHandles.Lookup?

Это не работает:

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 
[email protected] 

ответ

4

Как я знаю int[].class не имеет конструктора, поэтому он не доступен через отражение как минимум.

Вместо этого, вы можете попытаться получить MethodHandle на фабричный метод массива:

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

и создать массив, вызвав его.

+2

Только что проверил, что 'ИНТ [] :: нового 'генерирует в методе синтеза байт-кода, например' Object lambda $ MR $ new $ new $ 4ffde7b3 $ 1 (int len) {return new int [len]; } '. –

+0

В контексте вопроса вы наверняка хотите связать '.bindTo (int.class) .asType (MethodType.methodType (int []. Class, int.class))', чтобы получить желаемый дескриптор, представляющий 'int [] :: new', т. е. вы можете использовать его как 'int [] array = (int []) mh.invokeExact (42);' then – Holger

+0

Спасибо всем. Это сработало для меня: 'MethodHandles.insertArguments (lookup.findStatic (Array.class," newInstance ", MethodType.methodType (Object.class, Class.class, int.class)), 0, int.class)' – Archie

1

Похоже, что @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] 
    } 
} 

Нечто подобное на самом деле выполняется Java компилятором при компиляции int[]::new ссылки на метод: помощник частный метод создан. Вы можете проверить путем компиляции следующего класса:

import java.util.function.*; 

public class Test { 
    IntFunction<int[]> fn = int[]::new; 
} 

javap -p -c Test Running вы увидите, что помощник частного метод генерируются и связан, как MethodHandle к invokedynamic:

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