MethodHandle

JasonTam發表於2018-10-09

Java MethodHandle

   Java7在JSR 292中增加了對動態型別語言的支援,使得java也可以像C語言那樣將方法作為引數傳遞。

   在java.lang.invoke包中MethodHandle作用類似於反射中的Method類,但它比Method類要更加靈活和輕量級。

   Reflection是java api層面的反射呼叫,而MethodHandle則是jvm層面支援呼叫。因此Reflection是重量級,MethodHandle則是輕量級的。下面來看看怎麼使用
複製程式碼

通過MethodHandle進行方法呼叫一般需要:

  1. 建立MethodType物件,指定方法的簽名(即方法引數以及方法返回值的型別)。
  2. 在MethodHandles.Lookup中查詢型別為MethodType的MethodHandle;
  3. 傳入方法引數並呼叫MethodHandle.invoke或者MethodHandle.invokeExact方法。

MethodType

通過該物件設定方法的返回值以及引數列表中的型別。

第一個引數是返回型別,後面的剩餘引數是方法的引數型別。

MethodType.methodType(Class<?>class,Class<?>class1);
複製程式碼

Lookup

 通過findXX方法可以得到相應的MethodHandle。
複製程式碼

invoke

 invokeExact:呼叫此方法與直接呼叫底層方法一樣,需要做到引數型別精確匹配;

 invoke:引數型別鬆散匹配,通過asType自動適配;
複製程式碼

示例程式碼:

public class MethodHandleTest {

    public String toString(String s){
        return "Hello"+s+"MethodHandle";
    }


    public static void main(String[] args) {
        MethodHandleTest mht = new MethodHandleTest();
        MethodHandle mh = getString();
        try {
            String o = (String) mh.invokeExact(mht, "ssss");
            System.out.println(o);
        }catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        
        MethodHandle methodHandle = mh.bindTo(mht);
        try {
            String ssss = (String) methodHandle.invokeWithArguments("ssss");
            System.out.println(ssss);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }



    public static MethodHandle getString(){
        MethodType mt = MethodType.methodType(String.class,String.class);
        MethodHandle mh = null;
        try {
            mh = MethodHandles.lookup().findVirtual(MethodHandleTest.class,"toString",mt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mh;
    }
}
複製程式碼