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虛擬機》這本書,可以參悟很多!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章