Java Lambda及InvokedDynamic调用探秘(三)

这次我们来探究一下其它情况。

package com.github.wanggancheng;
import java.util.function.Consumer;
public class InvokeDynamicDemo {

    public static void output(String s){

        System.out.println(s);
    }

    public static void main(String[] args) {

        Consumer consumer=InvokeDynamicDemo::output;
        consumer.accept("Lambda demo");
    }
}

从上面的代码可以看出,与先前的主要差异为:用类静态方法来替代java Lambda。我们反编译class文件的方法信息如下:

public class com.github.wanggancheng.InvokeDynamicDemo {
  public com.github.wanggancheng.InvokeDynamicDemo();
  public static void output(java.lang.String);
  public static void main(java.lang.String[]);
}

从上面的信息来看,并没有自动添加什么方法。我们来看看main方法的字节码信息。

 public static void main(java.lang.String[]);
    Code:
       0: invokedynamic #4,  0              // InvokeDynamic #0:accept:()Ljava/util/function/Consumer;
       5: astore_1
       6: aload_1
       7: ldc           #5                  // String Lambda demo
       9: invokeinterface #6,  2            // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
      14: return

从上面可以看出第一条指令还是invokedynamic,有先前的例子没有什么差别。我们来看更具体的字节码信息。

BootstrapMethods:
  0: #36 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #37 (Ljava/lang/Object;)V
      #38 invokestatic com/github/wanggancheng/InvokeDynamicDemo.output:(Ljava/lang/String;)V
      #39 (Ljava/lang/String;)V

从第1个bootstrapmethod来看,与第1篇文章中的示例的bootstrapmethod的差异是第2个参数。先前的实例中第2个参数是调用编译器自动生成的一个静态方法ambda$main$0。

我们来看看一个稍复杂的例子。

package com.github.wanggancheng;
import java.util.function.Consumer;
public class InvokeDynamicInstanceMethodDemo {

    public void output(String s){

        System.out.println(s);
    }

    public static void main(String[] args) {

        InvokeDynamicInstanceMethodDemo instance = new InvokeDynamicInstanceMethodDemo();
        Consumer consumer=instance::output;
        consumer.accept("Lambda demo");
    }
}

反编译此类的class文件,可以发现也没有添加新方法。还是重点来看看bootstrap_method方法信息。

BootstrapMethods:
  0: #41 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #42 (Ljava/lang/Object;)V
      #43 invokevirtual com/github/wanggancheng/InvokeDynamicInstanceMethodDemo.output:(Ljava/lang/String;)V
      #44 (Ljava/lang/String;)V

重点差别为#43,表明调用类型为invokevirtual而非invokestatic。

invokedynamice_info的信息如下:

#7 = InvokeDynamic      #0:#45         // #0:accept:(Lcom/github/wanggancheng/InvokeDynamicInstanceMethodDemo;)Ljava/util/function/Consumer;

从上面的信息可以看出,与先前的示例的主要差别为invokedType中包含实例方法引用的类实例作为参数。

我们在运行时把自动生成的类dump出来,反编译信息如下。

package com.github.wanggancheng;

import java.lang.invoke.LambdaForm.Hidden;
import java.util.function.Consumer;

// $FF: synthetic class
final class InvokeDynamicInstanceMethodDemo$$Lambda$1 implements Consumer {
    private final InvokeDynamicInstanceMethodDemo arg$1;

    private InvokeDynamicInstanceMethodDemo$$Lambda$1(InvokeDynamicInstanceMethodDemo var1) {
        this.arg$1 = var1;
    }

    private static Consumer get$Lambda(InvokeDynamicInstanceMethodDemo var0) {
        return new InvokeDynamicInstanceMethodDemo$$Lambda$1(var0);
    }

    @Hidden
    public void accept(Object var1) {
        this.arg$1.output((String)var1);
    }
}

这个自动合成的类之构造方法有一个InvokeDynamicInstanceMethodDemo。这个参数就是Consumer引用的实例方法对应的类实例。

跟踪到InnerClassLambdaMetaFactory的buildCallSite方法。

CallSite最终指向的Method为NAME_FACTORY。这个常量固定为"get$Lambda"。

你可能感兴趣的:(Java Lambda及InvokedDynamic调用探秘(三))