lambda与匿名内部类

Posted 白豆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lambda与匿名内部类相关的知识,希望对你有一定的参考价值。

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()进行分析
image-20210510223438752

调用类的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的形式将引用到的外部对象保存起来。

以上是关于lambda与匿名内部类的主要内容,如果未能解决你的问题,请参考以下文章

Lambda 表达式与匿名内部类

lambda表达式与匿名内部类的简单转换

JAVA基础知识|lambda与stream

Java的Lambda表达式

函数式编程-Lambda与Stream

Lambda01 编程范式lambda表达式与匿名内部类lambda表达式的写法