1. 背景
JAVA中的Lambda表达式是JAVA 8中引入的,字节码层级是通过invokedynamic指令执行的,JVM在运行时动态创建类,并通过方法句柄调用的。
而Kotlin同时支持JAVA 1.6和Lambda表达式,由于invokedynamic指令是JAVA 7引入的,显然不可能和JAVA中Lambda表达式采用相同的实现机制。
本文是通过反编译协程相关class文件,分析Kotlin Lambda的实现原理。
2 Kotlin代码 T2.kt
第一个Lambda代码
fun main() {
val testf = { x:Int ->
val y = x + 1
y
}
println(testf(100))
}
输出结果
101
3. 字节码
T2.kt编译后出现两个class文件T2kt.class和T2Kt testf$1.class
3.1 T2kt.class
public final class T2Kt {
public static final void main();
Code:
0: getstatic #15 // Field T2Kt$main$testf$1.INSTANCE:LT2Kt$main$testf$1;
3: checkcast #17 // class kotlin/jvm/functions/Function1
6: astore_0
7: aload_0
8: bipush 100
10: invokestatic #23 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
13: invokeinterface #27, 2 // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
18: checkcast #29 // class java/lang/Number
21: invokevirtual #33 // Method java/lang/Number.intValue:()I
24: istore_1
25: iconst_0
26: istore_2
27: getstatic #39 // Field java/lang/System.out:Ljava/io/PrintStream;
30: iload_1
31: invokevirtual #45 // Method java/io/PrintStream.println:(I)V
34: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #9 // Method main:()V
3: return
}
3.1.1 public static void main(java.lang.String[]) main
自动创建了public static void main(java.lang.String[]) main方法,通过invokestatic字节码调用public static final void main方法。
3.1.2 public static final void main
此方法对应于T2.kt中的fun main方法
- 0:读取静态属性#15,为内部匿名类T2Kt testf$1的引用
- 3:检查是否能强制类型转换到kotlin/jvm/functions/Function1
- 13:调用内部匿名类的Function1.invoke方法
3.2 T2kt$main$1.class
T2kt$main$1继承了抽象类kotlin.jvm.internal.Lambda,并实现了接口kotlin.jvm.functions.Function1
3.2.1 public java.lang.Object invoke(java.lang.Object)
Lambda表达式调用入口
0: aload_0
1: aload_1
2: checkcast #11 // class java/lang/Number
5: invokevirtual #15 // Method java/lang/Number.intValue:()I
8: invokevirtual #18 // Method invoke:(I)I
11: invokestatic #24 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: areturn
- 0-5:加载入参到操作数栈
- 8:调用静态方法invoke,即Lambda表达式的具体逻辑
3.2.2 public final int invoke(int)
本方法为Lambda表达式的具体逻辑
0: iload_1
1: iconst_1
2: iadd
3: istore_2
4: iload_2
5: ireturn
- 0-1:加载局部变量表数据到操作数栈
- 2:栈顶数据相加
4. 总结
- Kotlin由于需要兼容JDK 1.6,它的Lambda表达式的实现是通过在编译期创建了一个内部匿名类,继承了抽象类kotlin.jvm.internal.Lambda,并实现了接口kotlin.jvm.functions.Function1;与JAVA中的Lambda表达式机制不同。