Java7 新特性:MethodHandler,MethodHandles,MethodHandles.Lookup用法详解

相关类介绍

MethodType类

MethodType是不可变类,提供了对方法所有输入参数和输出参数的描述。创建MethodType类实例的方法是调用静态方法MethodType.methodType(),该方法的第一个参数是方法的返回类型,之后的所有参数都是方法的参数类型。MethodType类通过静态方法MethodType.methodType创建。

// 创建一个MethodType类型对象,其返回值是String,第一个参数类型是char,第二个参数类型是char
mt = MethodType.methodType(String.class, char.class, char.class);

MethodHandle类

MethodHandle类提供了对类方法的反射调用。常用的方法有invokeinvokeExactinvoke方法检查对象的相应方法时如果发现参数类型/返回类型不匹配会首先调用MethodHandleasType方法将原来的参数类型转换为方法要求的参数类型,之后在接着调用方法。
invokeinvokeExact方法的参数都是可变参数,当MethodHandle实例表示的是静态方法时,传入的参数都是静态方法的参数;当MethodHandle实例表示的是实例方法时,传入的参数第一个是实例,之后的才是方法参数。

MethodHandles类

MethodHandles类提供了一系列静态方法生成MethodHandle类。该类提供的静态方法可以归结微以下三类:

  1. 查找方法,帮助创建方法和属性的MethodHandle类;
  2. 组合器方法,用于将现有的MethodHandle实例转换成新的实例;
  3. 用于创建模拟其他JVM操作的MethodHandler实例的工厂方法。

Methodhandles.Lookup类

该类的主要作用是创建MethodHandle的工厂类。该类在创建MethodHandle实例时会检查调用者是否对反射的方法有相应的调用权限。创建Lookup对象的方法有以下两种:

  1. MethodHandles.lookup()创建一个Lookup对象,该对象可以创建所有访问权限的方法,包括publicprotectedprivatedefault
  2. MethodHandles.publicLookup() 创建一个Lookup对象,该对象只能创建具有public访问权限的方法。

举例

示例一

Object x, y; String s; int i;
MethodType mt; MethodHandle mh;
MethodHandles.Lookup lookup = MethodHandles.lookup();
// mt is (char,char)String
mt = MethodType.methodType(String.class, char.class, char.class);
mh = lookup.findVirtual(String.class, "replace", mt);
s = (String) mh.invokeExact("daddy",'d','n');
// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
assertEquals(s, "nanny");
// weakly typed invocation (using MHs.invoke)
s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
assertEquals(s, "savvy");
// mt is (Object[])List
mt = MethodType.methodType(java.util.List.class, Object[].class);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
assert(mh.isVarargsCollector());
x = mh.invoke("one", "two");
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assertEquals(x, java.util.Arrays.asList("one","two"));
// mt is (Object,Object,Object)Object
mt = MethodType.genericMethodType(3);
mh = mh.asType(mt);
x = mh.invokeExact((Object)1, (Object)2, (Object)3);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
assertEquals(x, java.util.Arrays.asList(1,2,3));
// mt is ()int
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
// invokeExact(Ljava/util/List;)I
assert(i == 3);
mt = MethodType.methodType(void.class, String.class);
mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
mh.invokeExact(System.out, "Hello, world.");
// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V

示例二(来自Mybatis的示例)

static {
    Method privateLookupIn;
    try {
        privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
    } catch (NoSuchMethodException e) {
        privateLookupIn = null;
    }
    privateLookupInMethod = privateLookupIn;

    Constructor<Lookup> lookup = null;
    if (privateLookupInMethod == null) {
        // JDK 1.8
        try {
        lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
        lookup.setAccessible(true);
        } catch (NoSuchMethodException e) {
        throw new IllegalStateException(
            "There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.",
            e);
        } catch (Exception e) {
            lookup = null;
        }
    }
    lookupConstructor = lookup;
}

以上代码首先反射获取MethodHandle.privateLookupIn方法,如果没有该方法的话说明运行的jre版本在1.8以下,因此反射获取Lookup对象的构造方法Lookup(Class, int),该构造方法的源码为:

private Lookup(Class<?> lookupClass, int allowedModes) {
	this.lookupClass = lookupClass;
	this.allowedModes = allowedModes;
}

第一个参数为查找方法的类,第二个参数为允许的模式。
MapperProxy接下来的代码中,我们发现方法getMethodHandleJava8使用属性lookupConstructor创建了参数methodMethodHadle对象。而传递给newInstance方法的参数ALLOWED_MODES即为允许的模式,该属性为MapperProxy的静态属性。

private MethodHandle getMethodHandleJava8(Method method)
      throws IllegalAccessException, InstantiationException, InvocationTargetException {
    final Class<?> declaringClass = method.getDeclaringClass();
    // 方法unreflectSpecial为反射的方法 method 创建对应的MethodHandle对象
    return lookupConstructor.newInstance(declaringClass, ALLOWED_MODES).unreflectSpecial(method, declaringClass);
}
private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
      | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;

可以看到ALLOWE_MODESMethodHandles中定义的四种方位权限的或,因此lookup对象的访问权限为所有的方法。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值