编译期:
- 生成invokedynamic指令和bootstrap方法(由java.lang.invoke.LambdaMetafactory.metafactory方法实现)
运行时:
- invokedynamic指令调用metafactory方法。 它会返回一个CallSite, 此CallSite返回目标类型的一个匿名实现类, 此类关联编译时产生的方法。CallSIte 里面包含一个MethodHandler(1.8引入)
- 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);
}
}
网友评论