【Kotlin】函数 ⑦ ( 内联函数 | Lambda 表达式弊端 | “ 内联 “ 机制避免内存开销 - 将使用 Lambda 表达式作为参数的函数定义为内联函数 | 内联函数本质 - 宏替换 )

2023-03-30 18:37:11 浏览数 (1)

文章目录

  • 一、内联函数
    • 1、Lambda 表达式弊端
    • 2、" 内联 " 机制避免内存开销
    • 3、内联函数本质 - 编译时宏替换
    • 4、内联函数不能递归
  • 二、普通函数代码示例
  • 三、内联函数代码示例

一、内联函数


1、Lambda 表达式弊端

Lambda 表达式弊端 :

Lambda 表达式 的 灵活使用 , 是以 牺牲内存开销为代价的 ;

在 Java 虚拟机中 , Lambda 表达式 是以 实例对象 的形式 , 存储在堆内存中的 , 这就产生了内存开销 ;

2、" 内联 " 机制避免内存开销

" 内联 " 机制避免内存开销 :

在 Kotlin 语言中提供了一种 " 内联 " 机制 ,

解决了上面的 Lambda 表达式的 内存开销 问题 ,

将 使用 Lambda 表达式 作为参数的函数 定义为 inline 内联函数 ,

Java 虚拟机就 不会再为 lambda 表达式 在堆内存中 创建 实例对象 了 ,

这样就 避免了 Lambda 表达式 的内存开销 ;

3、内联函数本质 - 编译时宏替换

内联函数使用 :

在使用 Lambda 表达式的时候 ,

Kotlin 编译器直接将 inline 内联函数 的 函数体 直接拷贝到 使用位置 ;

内联函数 类似于 C 语言中的 预编译指令 宏定义 , 在编译时直接替换拷贝宏定义内容 ;

Kotlin 中的 内联函数 也是一种 编译时 进行 宏替换的操作 ;

4、内联函数不能递归

内联函数不能递归 :

如果 将函数 定义为 内联函数 ,

则该函数 不能进行递归操作 ,

递归操作 会导致 函数体的 无限复制粘贴 ,

编译器会报警 ;

二、普通函数代码示例


代码示例 : 下面的代码中 studentDoSomething 是普通函数 ;

代码语言:javascript复制
fun main() {
    // 定义函数类型变量, 之后作为函数参数传递给函数
    val actionFun = { name: String, age: Int ->
        "student $name $age years old, say hello"
    }

    // 调用 studentDoSomething 函数, 输入姓名, 年龄, 执行的操作
    studentDoSomething("Tom", 18, actionFun);
}

fun studentDoSomething(name: String, age: Int,
                       action: (String, Int) -> String) {
    val act = action(name, age);
    println(act)
}

将字节码转换为 Java 代码内容如下 :

代码语言:javascript复制
import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 1, 16},
   bv = {1, 0, 3},
   k = 2,
   d1 = {"u0000u001cnu0000nu0002u0010u0002nu0002bu0002nu0002u0010u000enu0000nu0002u0010bnu0000nu0002u0018u0002nu0000u001au0006u0010u0000u001au00020u0001u001a0u0010u0002u001au00020u00012u0006u0010u0003u001au00020u00042u0006u0010u0005u001au00020u00062u0018u0010u0007u001au0014u0012u0004u0012u00020u0004u0012u0004u0012u00020u0006u0012u0004u0012u00020u00040b¨u0006t"},
   d2 = {"main", "", "studentDoSomething", "name", "", "age", "", "action", "Lkotlin/Function2;", "KotlinDemo"}
)
public final class HelloKt {
   public static final void main() {
      Function2 actionFun = (Function2)null.INSTANCE;
      studentDoSomething("Tom", 18, actionFun);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }

   public static final void studentDoSomething(@NotNull String name, int age, @NotNull Function2 action) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      Intrinsics.checkParameterIsNotNull(action, "action");
      String act = (String)action.invoke(name, age);
      boolean var4 = false;
      System.out.println(act);
   }
}

三、内联函数代码示例


代码示例 : 下面的代码中 studentDoSomething 是内联函数 ;

代码语言:javascript复制
fun main() {
    // 定义函数类型变量, 之后作为函数参数传递给函数
    val actionFun = { name: String, age: Int ->
        "student $name $age years old, say hello"
    }

    // 调用 studentDoSomething 函数, 输入姓名, 年龄, 执行的操作
    studentDoSomething("Tom", 18, actionFun);
}

inline fun studentDoSomething(name: String, age: Int,
                       action: (String, Int) -> String) {
    val act = action(name, age);
    println(act)
}

将字节码转换为 Java 代码内容如下 :

代码语言:javascript复制
import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 1, 16},
   bv = {1, 0, 3},
   k = 2,
   d1 = {"u0000u001cnu0000nu0002u0010u0002nu0002bu0002nu0002u0010u000enu0000nu0002u0010bnu0000nu0002u0018u0002nu0000u001au0006u0010u0000u001au00020u0001u001a3u0010u0002u001au00020u00012u0006u0010u0003u001au00020u00042u0006u0010u0005u001au00020u00062u0018u0010u0007u001au0014u0012u0004u0012u00020u0004u0012u0004u0012u00020u0006u0012u0004u0012u00020u00040bHu0086b¨u0006t"},
   d2 = {"main", "", "studentDoSomething", "name", "", "age", "", "action", "Lkotlin/Function2;", "KotlinDemo"}
)
public final class HelloKt {
   public static final void main() {
      Function2 actionFun = (Function2)null.INSTANCE;
      String name$iv = "Tom";
      int age$iv = 18;
      int $i$f$studentDoSomething = false;
      String act$iv = (String)actionFun.invoke(name$iv, Integer.valueOf(age$iv));
      boolean var5 = false;
      System.out.println(act$iv);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }

   public static final void studentDoSomething(@NotNull String name, int age, @NotNull Function2 action) {
      int $i$f$studentDoSomething = 0;
      Intrinsics.checkParameterIsNotNull(name, "name");
      Intrinsics.checkParameterIsNotNull(action, "action");
      String act = (String)action.invoke(name, age);
      boolean var5 = false;
      System.out.println(act);
   }
}

0 人点赞