美文网首页
JAVA-Lambda调用过程

JAVA-Lambda调用过程

作者: AlanSun2 | 来源:发表于2019-09-19 14:04 被阅读0次

编译期:

  1. 生成invokedynamic指令和bootstrap方法(由java.lang.invoke.LambdaMetafactory.metafactory方法实现)

运行时:

  1. invokedynamic指令调用metafactory方法。 它会返回一个CallSite, 此CallSite返回目标类型的一个匿名实现类, 此类关联编译时产生的方法。CallSIte 里面包含一个MethodHandler(1.8引入)
  2. lambda表达式调用时会调用匿名实现类关联的方法,再调用相应的 lambda$main$0

我们来看下一个例子:

public class LambdaTest {
    public static void main(String[] args) {
        Consumer<String> consumer = s -> System.out.println(s);
        consumer.accept("lambda");
    }
}

反汇编 javap -c -p -v LambdaTest.class

Classfile /C:/Users/53479/OneDrive/workspace/study/target/classes/com/alan344/anonymoustest/LambdaTest.class
  Last modified 2019-9-19; size 1414 bytes
  MD5 checksum 251e70c1014667e618d7c8ba2d68afea
  Compiled from "LambdaTest.java"
public class com.alan344.anonymoustest.LambdaTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #8.#30         // java/lang/Object."<init>":()V
   #2 = InvokeDynamic      #0:#36         // #0:accept:()Ljava/util/function/Consumer;
   #3 = String             #37            // lambda
   #4 = InterfaceMethodref #38.#39        // java/util/function/Consumer.accept:(Ljava/lang/Object;)V
   #5 = Fieldref           #40.#41        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = Methodref          #42.#43        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #7 = Class              #44            // com/alan344/anonymoustest/LambdaTest
   #8 = Class              #45            // java/lang/Object
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               LocalVariableTable
  #14 = Utf8               this
  #15 = Utf8               Lcom/alan344/anonymoustest/LambdaTest;
  #16 = Utf8               main
  #17 = Utf8               ([Ljava/lang/String;)V
  #18 = Utf8               args
  #19 = Utf8               [Ljava/lang/String;
  #20 = Utf8               consumer
  #21 = Utf8               Ljava/util/function/Consumer;
  #22 = Utf8               LocalVariableTypeTable
  #23 = Utf8               Ljava/util/function/Consumer<Ljava/lang/String;>;
  #24 = Utf8               lambda$main$0
  #25 = Utf8               (Ljava/lang/String;)V
  #26 = Utf8               s
  #27 = Utf8               Ljava/lang/String;
  #28 = Utf8               SourceFile
  #29 = Utf8               LambdaTest.java
  #30 = NameAndType        #9:#10         // "<init>":()V
  #31 = Utf8               BootstrapMethods
  #32 = MethodHandle       #6:#46         // 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;
  #33 = MethodType         #47            //  (Ljava/lang/Object;)V
  #34 = MethodHandle       #6:#48         // invokestatic com/alan344/anonymoustest/LambdaTest.lambda$main$0:(Ljava/lang/String;)V
  #35 = MethodType         #25            //  (Ljava/lang/String;)V
  #36 = NameAndType        #49:#50        // accept:()Ljava/util/function/Consumer;
  #37 = Utf8               lambda
  #38 = Class              #51            // java/util/function/Consumer
  #39 = NameAndType        #49:#47        // accept:(Ljava/lang/Object;)V
  #40 = Class              #52            // java/lang/System
  #41 = NameAndType        #53:#54        // out:Ljava/io/PrintStream;
  #42 = Class              #55            // java/io/PrintStream
  #43 = NameAndType        #56:#25        // println:(Ljava/lang/String;)V
  #44 = Utf8               com/alan344/anonymoustest/LambdaTest
  #45 = Utf8               java/lang/Object
  #46 = Methodref          #57.#58        // 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;
  #47 = Utf8               (Ljava/lang/Object;)V
  #48 = Methodref          #7.#59         // com/alan344/anonymoustest/LambdaTest.lambda$main$0:(Ljava/lang/String;)V
  #49 = Utf8               accept
  #50 = Utf8               ()Ljava/util/function/Consumer;
  #51 = Utf8               java/util/function/Consumer
  #52 = Utf8               java/lang/System
  #53 = Utf8               out
  #54 = Utf8               Ljava/io/PrintStream;
  #55 = Utf8               java/io/PrintStream
  #56 = Utf8               println
  #57 = Class              #60            // java/lang/invoke/LambdaMetafactory
  #58 = NameAndType        #61:#65        // 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;
  #59 = NameAndType        #24:#25        // lambda$main$0:(Ljava/lang/String;)V
  #60 = Utf8               java/lang/invoke/LambdaMetafactory
  #61 = Utf8               metafactory
  #62 = Class              #67            // java/lang/invoke/MethodHandles$Lookup
  #63 = Utf8               Lookup
  #64 = Utf8               InnerClasses
  #65 = Utf8               (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;
  #66 = Class              #68            // java/lang/invoke/MethodHandles
  #67 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #68 = Utf8               java/lang/invoke/MethodHandles
{
  public com.alan344.anonymoustest.LambdaTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/alan344/anonymoustest/LambdaTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: invokedynamic #2,  0              // InvokeDynamic #0:accept:()Ljava/util/function/Consumer;
         5: astore_1
         6: aload_1
         7: ldc           #3                  // String lambda
         9: invokeinterface #4,  2            // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
        14: return
      LineNumberTable:
        line 11: 0
        line 12: 6
        line 13: 14
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      15     0  args   [Ljava/lang/String;
            6       9     1 consumer   Ljava/util/function/Consumer;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            6       9     1 consumer   Ljava/util/function/Consumer<Ljava/lang/String;>;

  private static void lambda$main$0(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: aload_0
         4: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         7: return
      LineNumberTable:
        line 11: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       8     0     s   Ljava/lang/String;
}
SourceFile: "LambdaTest.java"
InnerClasses:
     public static final #63= #62 of #66; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
  0: #32 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:
      #33 (Ljava/lang/Object;)V
      #34 invokestatic com/alan344/anonymoustest/LambdaTest.lambda$main$0:(Ljava/lang/String;)V
      #35 (Ljava/lang/String;)V

生成的实现类。通过设置命令:-Djdk.internal.lambda.dumpProxyClasses 保存实现类到文件
使用到了MethodHandler,Unsafe.defineAnonymousClass

package com.alan344.anonymoustest;

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

// $FF: synthetic class
final class LambdaTest$$Lambda$1 implements Consumer {
    private LambdaTest$$Lambda$1() {
    }

    @Hidden
    public void accept(Object var1) {
        LambdaTest.lambda$main$0((String)var1);
    }
}

相关文章

网友评论

      本文标题:JAVA-Lambda调用过程

      本文链接:https://www.haomeiwen.com/subject/mflructx.html