lambda与匿名内部类
当lambda表达式中引用到this,指示的是外部类的引用这个时候编译器会创建匿名内部方法,并且在程序运行期间动态的并加载内部类,可以使用java -Djdk.internal.lambda.dumpProxyClasses class文件名 来将运行时的的内部类的字节码输出对应的class文件。若是lambda没有使用外部类的引用filed等相关就创建静态内部方法。而匿名内部类的方式则是在javac编译时直接生成对应的内部类class字节码,并且创建相应的示例。
kotlin local function个人简介
private fun test() {
val a: (Int) -> Unit = {
}
a(2)
}
private fun test1() {
fun a(a: Int) {
}
a(2)
}
这两种方式都使用了本地函数,但它是如何实现的呢?我们看一下kotln的字节码
private final static test()V
L0
LINENUMBER 2 L0
GETSTATIC LambdaAndLocalFunKt$test$a$1.INSTANCE : LLambdaAndLocalFunKt$test$a$1;
CHECKCAST kotlin/jvm/functions/Function1
ASTORE 0
L1
LINENUMBER 4 L1
ALOAD 0
ICONST_2
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
INVOKEINTERFACE kotlin/jvm/functions/Function1.invoke (Ljava/lang/Object;)Ljava/lang/Object; (itf)
POP
L2
LINENUMBER 5 L2
RETURN
L3
LOCALVARIABLE a Lkotlin/jvm/functions/Function1; L1 L3 0
MAXSTACK = 2
MAXLOCALS = 1
==================================================================================================
final class LambdaAndLocalFunKt$test$a$1
extends kotlin/jvm/internal/Lambda
implements kotlin/jvm/functions/Function1 {
public final static LLambdaAndLocalFunKt$test$a$1; INSTANCE
// access flags 0x1041
public synthetic bridge invoke(Ljava/lang/Object;)Ljava/lang/Object;
ALOAD 0
ALOAD 1
CHECKCAST java/lang/Number
INVOKEVIRTUAL java/lang/Number.intValue ()I
INVOKEVIRTUAL LambdaAndLocalFunKt$test$a$1.invoke (I)V
GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
ARETURN
MAXSTACK = 2
MAXLOCALS = 2
public final invoke(I)V
// annotable parameter count: 1 (visible)
// annotable parameter count: 1 (invisible)
L0
LINENUMBER 3 L0
RETURN
L1
LOCALVARIABLE this LLambdaAndLocalFunKt$test$a$1; L0 L1 0
LOCALVARIABLE it I L0 L1 1
MAXSTACK = 0
MAXLOCALS = 2
}
test()跟test1()大同小异我们只对其中之一test()进行分析
调用类的invoke(object)方法,在该方法中调用invoke(Int)方法。
我们来考虑在方法中持有外部局部变量的情况
private fun test() {
val s = 2
val a: (Int) -> Unit = {
println(it)
println(s)
}
a(2)
}
private final static test()V
L0
LINENUMBER 2 L0
ICONST_2
ISTORE 0
L1
LINENUMBER 3 L1
NEW LambdaAndLocalFunKt$test$a$1
DUP
ILOAD 0
INVOKESPECIAL LambdaAndLocalFunKt$test$a$1.<init> (I)V
CHECKCAST kotlin/jvm/functions/Function1
ASTORE 1
我们只关注重点代码
这次不同的是要使用new创建对象并且调用init()方法对对象进行初始化,我们来观察一下对象的初始化。
<init>(I)V
ALOAD 0
ILOAD 1
PUTFIELD LambdaAndLocalFunKt$test$a$1.$s : I
ALOAD 0
ICONST_1
INVOKESPECIAL kotlin/jvm/internal/Lambda.<init> (I)V
RETURN
MAXSTACK = 2
MAXLOCALS = 2
// access flags 0x1010
final synthetic I $s
很明显他会将其以final的形式将引用到的外部对象保存起来。