2016-03-18 11 views
5

Come si ottiene MethodHandle per un costruttore di array come int[]::new?Come si cerca un costruttore di array MethodHandle con MethodHandles.Lookup?

Questo non funziona:

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

Essa si traduce in questo:

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 

Né questo:

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

Sembra di trovare il costruttore per Object invece:

MethodHandle()Object 
[email protected] 

risposta

4

Come noto, lo int[].class non dispone di un costruttore, quindi non è disponibile tramite riflessione almeno.

Invece, si può cercare di ottenere MethodHandle il metodo factory di Array:

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

e creare un array chiamando esso.

+2

appena controllato che 'int [] :: nuova 'genera nel metodo sintetico bytecode come' Oggetto lambda $ MR $ nuovo $ nuovo $ 4ffde7b3 $ 1 (int len) {return new int [len]; } '. –

+0

Nel contesto della domanda, si vuole sicuramente concatenare un '.bindTo (int.class) .asType (MethodType.methodType (int []. Class, int.class))' per ottenere l'handle desiderato che rappresenta un 'int [] :: new' logic, cioè puoi usarlo come 'int [] array = (int []) mh.invokeExact (42);' then – Holger

+0

Grazie a tutti. Questo ha funzionato per me: 'MethodHandles.insertArguments (lookup.findStatic (Array.class," newInstance ", MethodType.methodType (Object.class, Class.class, int.class)), 0, int.class)' – Archie

1

Sembra che @MaximSIvanov abbia ragione: non esiste un modo integrato per ottenere tale handle del metodo. Tuttavia nulla vi impedisce di creare un metodo speciale per questo scopo e fornire una maniglia a questo metodo:

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

Qualcosa di simile viene eseguito effettivamente da compilatore Java quando si compila int[]::new metodo di riferimento: si crea aiutante metodo privato. Check compilando la seguente classe:

import java.util.function.*; 

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

esecuzione javap -p -c Test vedrete che metodo privato di supporto viene generato e legato come MethodHandle a invokedynamic:

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