Kotlin字节码解析-2 Lambda表达式

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 m a i n main maintestf$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 m a i n main maintestf$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表达式机制不同。

你可能感兴趣的:(JAVA语言)