2016-03-18 12 views
5

Wie bekomme ich die MethodHandle für einen Array-Konstruktor wie int[]::new?Wie suche ich einen Array-Konstruktor MethodHandle mit MethodHandles.Lookup?

funktioniert das nicht:

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

Es ergibt dies:

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 

auch nicht dies:

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

Es den Konstruktor für Object statt zu finden scheint:

MethodHandle()Object 
[email protected] 

Antwort

4

Wie ich weiß int[].class hat keinen Konstruktor, so ist es nicht mindestens über Reflexion verfügbar.

Stattdessen können Sie versuchen MethodHandle auf Array der Factory-Methode zu erhalten:

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

und ein Array erstellen, indem sie aufruft.

+2

geprüft Nur, dass 'int [] :: neu 'generiert in bytecode eine synthetische Methode wie' Objekt Lambda $ MR $ neu $ neu $ 4ffde7b3 $ 1 (int len) {return new int [len]; } '. –

+0

Im Zusammenhang mit der Frage wollen Sie sicher eine '.bindTo (int.class) .asType (MethodType.methodType (int []. Class, int.class))' ketten, um das gewünschte Handle zu erhalten, das ein 'int darstellt [] :: new' logic, dh Sie können es verwenden wie 'int [] array = (int []) mh.invokeExact (42);' dann – Holger

+0

Danke an alle. Das funktionierte für mich: 'MethodHandles.insertArguments (lookup.findStatic (Array.class," newInstance ", MethodType.methodType (Object.class, Class.class, int.class)), 0, int.class)' – Archie

1

Scheint, dass @MaximSIvanov hat Recht: Es gibt keine integrierte Möglichkeit, solche Methode zu erhalten. Nichts hindert Sie jedoch von einem speziellen Verfahren zu diesem Zweck die Schaffung und bieten einen Griff an dieser Methode:

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

ähnlich tatsächlich etwas von Java-Compiler ausgeführt wird, wenn Sie int[]::new Methode Referenz kompilieren: Helfer private Methode erstellt. Diese können Sie überprüfen, indem Sie die folgende Klasse kompilieren:

import java.util.function.*; 

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

javap -p -c Test Laufen Sie, dass Helfer private Methode sehen werden erzeugt und als MethodHandle zu invokedynamic verbunden:

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