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虚拟机》这本书,可以参悟很多!!!

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