
3.2.7 换个角度看Lambda表达式
Kotlin的代码最终还是会编译成.class文件,由JVM进行加载。
1.示例1
我们曾经讲过,sum这个函数本质上实现了kotlin.jvm.functions.Function2接口,即:

如图3-4所示,可以查看一下Kotlin Bytecode,会发现它确实是这样的。

图3-4 查看Kotlin函数的字节码
如图3-5所示,再来查看sum(3, 5)的使用,发现它调用了Function2的invoke()方法。

图3-5 sum(3, 5)函数的字节码
换一种工具,如图3-6所示,使用JD-GUI将上述Kotlin代码反编译成Java代码会更加清晰。

图3-6 使用JD-GUI进行反编译
有多种方式可以反编译成字节码,例如使用IDEA自带的工具Tools->Kotlin->Show Kotlin Bytecode,或者使用javap命令反编译.class文件,亦或者使用BytecodeViewer反编译.class文件,都能够将Kotlin的代码反编译成字节码。有时字节码看不清晰,反编译成Java代码效果会更好。
2.示例2
下面是使用filter、forEach的例子,它们都是高阶函数。

如图3-7所示,反编译成Java的代码之后,会发现并没有实现FunctionN接口。

图3-7 反编译高阶函数
这是因为在Kotlin的filter、forEach函数中都使用了inline,表明这些函数是内联函数。所以,这些函数不需要实例化FunctionN接口,内联函数的特性将会在第4章讲述。

Lambda表达式会实现一个FunctionN接口,N的大小由表达式的参数个数决定。在Kotlin 1.3之前不能大于23个,只能是0~22,在Kotlin 1.3之后放宽了限制。
如果Lambda表达式中使用函数作为参数,并且整个高阶函数使用inline修饰,Lambda表达式就不必实现FunctionN接口。