1. 程式人生 > >Java動態語言特性之MethodHandle MethodHandles MethodType的簡單使用

Java動態語言特性之MethodHandle MethodHandles MethodType的簡單使用

對於子類呼叫父類的方法我們用super.Method()即可,但是倘若我們想呼叫其祖先類,並且在不改變其繼承關係以及祖先和父類的程式碼的時候,該怎麼辦呢,程式碼樣列如下:給大家三個類,可以先去了解再來熟悉下面的程式碼

  • MethodHandle 它是可對直接執行的方法或者欄位或者構造方法的型別的引用,或者說他是一個有能力安全呼叫方法的物件。
  • MethodHandles 它是僅操作或返回方法控制代碼的靜態方法的類。
  • MethodType 他是表示方法簽名型別的不可變物件。每個MethodHandle都有一個MethodType例項,用來指明返回型別和引數型別。
package vip.wulang.test;

/**
 * @author coolerwu on 2018/8/13.
 * @version 1.0
 * @time 20:58
 */
public class ParentTest {
    class GrandFather {
        public void thinking() {
            System.out.println("i am grandfather.");
        }
    }

    class Father extends GrandFather {
        @Override
public void thinking() { System.out.println("i am father."); } } class Son extends Father { @Override public void thinking() { //如何呼叫GrandFather } } public static void main(String[] args) { new ParentTest().new Son
().thinking(); } }

第一種方法

package vip.wulang.test;

/**
 * @author coolerwu on 2018/8/13.
 * @version 1.0
 * @time 20:58
 */
public class ParentTest {
    class GrandFather {
        public void thinking() {
            System.out.println("i am grandfather.");
        }
    }

    class Father extends GrandFather {
        @Override
        public void thinking() {
            System.out.println("i am father.");
        }
    }

    class Son extends Father {
        @Override
        public void thinking() {
            GrandFather grandFather = new GrandFather();
            grandFather.thinking();
        }
    }

    public static void main(String[] args) {
        new ParentTest().new Son().thinking();
    }
}
//輸出結果
//i am grandfather.

第二種方法也就是今天我要講的這種,其他的反射之類的各位自行去解決

package vip.wulang.test;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;

/**
 * @author coolerwu on 2018/8/13.
 * @version 1.0
 * @time 20:58
 */
public class ParentTest {
    class GrandFather {
        public void thinking() {
            System.out.println("i am grandfather.");
        }
    }

    class Father extends GrandFather {
        @Override
        public void thinking() {
            System.out.println("i am father.");
        }
    }

    class Son extends Father {
        @Override
        public void thinking() {
            MethodType methodType = MethodType.methodType(void.class);
            try {
                Constructor<MethodHandles.Lookup> constructor = 
	                MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
                constructor.setAccessible(true);
                MethodHandles.Lookup instance = constructor.newInstance(GrandFather.class, -1);
                MethodHandle methodHandle = 
	                instance.findSpecial(
		                GrandFather.class, "thinking", methodType, GrandFather.class);
                methodHandle.invoke(this);
            } catch (Exception e) {
                e.printStackTrace();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        new ParentTest().new Son().thinking();
    }
}
//輸出結果
//i am grandfather.

是不是很神奇

其中MethodType.methodType();第一個引數是返回型別,後面的為引數型別。MethodHandles.Lookup中的構造方法我需要
的是private Lookup(Class<?> lookupClass, int allowedModes)所以我利用了反射來獲取到例項,也可以通過反射
獲取這個static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);都是一樣的,主要是因為在
Lookup類中TRUSTED代表可信任的,可以訪問任何方法,TRUSTED值為-1,而instance.findSpecial意思就是去這個類尋
找帶有thinking名字的並且引數型別以及方法型別一樣的,最後invoke

這種方法模式使用了invokedynamic指令,使其具有動態語言的特性,用空可以去看看《深入理解Java虛擬機器》這本書,可以參悟很多!!!