本文章主要介绍了java中的MethodHandler入门,具有不错的的参考价值,希望对您有所帮助,如解说有误或未考虑完全的地方,请您留言指出,谢谢!

介绍

MethodHandler,翻译过来就是方法句柄,是java7提供的jsr292的一部分,为了支持动态方法的调用,主要是java.lang.invoke包。

使用

public class Client { 
  public static void main(String[] args) throws Throwable { 
    MethodHandles.Lookup lookup = MethodHandles.lookup(); 
//获取String类中静态方法valueOf对应的方法句柄 
    MethodHandle valueOfMethodHandler = lookup.findStatic(String.class, "valueOf", MethodType.methodType(String.class, int.class)); 
//执行方法句柄 
    String result = (String) valueOfMethodHandler.invokeExact(12); 
    System.out.println(result); 
  } 
} 

Lookup可以简单看做查找方法句柄的工具,MethodType表示一个方法类型,包括返回值和参数列表。方法句柄相对于反射来说,更加的轻量级。

动态调用点(CallSite)

java7新增了一个字节码invokedynamic,可以在运行期动态决定调用的方法,区别于之前的invokestatic(静态方法调用),invokespecial(构造方法,私有方法,父类方法),invokevirtual(实例方法),invokeinterface(接口方法),不过在java7下javac不支持生成invokedynamic,java8中可以通过lambda来生成。

public class Client { 
  public static void main(String[] args) throws Throwable { 
    MethodType type = MethodType.methodType(String.class, int.class, int.class); 
    MethodHandles.Lookup lookup = MethodHandles.lookup(); 
    MethodHandle handle = lookup.findVirtual(String.class, "substring", type); 
    ConstantCallSite callSite = new ConstantCallSite(handle); 
    MethodHandle invoker = callSite.dynamicInvoker(); 
    String result = (String) invoker.invoke("Hello", 0, 3); 
    System.out.println(result); 
  } 
} 

以上一个CallSite的小例子,会输出Hel。

public class Client { 
  public static void main(String[] args) { 
    updateAfterPay(info -> System.out.println(info)); 
  } 
 
  private static void updateAfterPay(Consumer<String> consumer) { 
    System.out.println("start ..."); 
    consumer.accept("pay success"); 
    System.out.println("end ..."); 
  } 
} 

这是lambda表达式的一个小例子,我们看一下反编译后的结果

public class Client { 
    public static void main(String[] args) {       Client.updateAfterPay((Consumer<String>)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)V, lambda$main$0(java.lang.String ), (Ljava/lang/String;)V)()); 
    } 
 
    private static void updateAfterPay(Consumer<String> consumer) { 
        System.out.println("start ..."); 
        consumer.accept("pay success"); 
        System.out.println("end ..."); 
    } 
//这个方法是编译器帮我们创建的,就是lambda处理的内容 
    private static /* synthetic */ void lambda$main$0(String info) { 
        System.out.println(info); 
    } 
} 

看一下LambdaMetafactory的文档介绍

Methods to facilitate the creation of simple "function objects" that 
 * implement one or more interfaces by delegation to a provided {@link MethodHandle}, 
 * possibly after type adaptation and partial evaluation of arguments.  These 
 * methods are typically used as <em>bootstrap methods</em> for {@code invokedynamic} 
 * call sites, to support the <em>lambda expression</em> and <em>method 
 * reference expression</em> features of the Java Programming Language. 

可以简单理解为一个创建动态调用点CallSite的工具,metafactory方法的返回值就是CallSite。
通过javap看一下反编译的字节码

从这我们可以看出lambda表达式的实现原理大概就是将lambda转换成一个动态调用点的调用,动态调用点又会代理给方法句柄MethodHandle,在我们这个例子中就是lambda$main$0的方法句柄。


发布评论
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

java中的CompileAPI入门及使用知识解答
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。