2016-03-18 16 views
5

如何獲得像int[]::new這樣的數組構造函數MethodHandle如何使用MethodHandles.Lookup查找數組構造函數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 
[email protected] 

回答

4

據我所知int[].class沒有構造函數,所以它至少不能通過反射獲得。

相反,你可以嘗試讓MethodHandle對Array的工廠方法:

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

,並通過調用它創建一個數組。

+2

只是檢查了'INT [] ::新'生成字節碼合成方法,比如'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);'然後 – 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你會看到生成該助手私有方法和鏈接爲MethodHandle到invokedynamic

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