zoukankan      html  css  js  c++  java
  • 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的方法句柄。

  • 相关阅读:
    iOS无限循环滚动scrollview
    SDWebImage实现原理(怎么实现图片缓存器)
    CocoaPods第三方库管理 iOS
    什么时候会报unrecognized selector的异常?
    iOS提交后申请加急审核
    iOS 个人账号 iOS APP Development 灰色不可选
    Xcode6 管理provisioning profile
    iOS苹果推送功能实现步骤
    蓝桥杯 幸运数
    hihocoder编程练习赛52-3 部门聚会
  • 原文地址:https://www.cnblogs.com/strongmore/p/13362599.html
Copyright © 2011-2022 走看看