Kotlin 中的内联:inline

258 阅读3分钟

本文重点:

  • 什么是内联,如何声明为内联函数,内联的应用场景,内联的底层实现原理,如何在IDEA中查看Kotlin程序对应的Java代码,什么是函数引用,函数引用的应用场景与具体使用;

前置知识铺垫:

  • Kotlin文件最终会编译为 Java文件后执行

  • 在IDEA中如何 查看Kotlin对应的 Java代码

    • 第一步:获取Kotlin对应的字节码文件

      image-20220602232846533

    • 第二步:将字节码文件转成 Java代码(点击反编译按钮)

      image-20220602233028061

    • 即可查看Kotlin原文件与对应的 Java文件

      image-20220602233130821

本文概述:当函数参数为Lamda,尽量使用inline

  • 什么是内联:函数A作为函数B的参数

  • 什么情况下使用内联:函数参数为Lamda表达式

  • 如何使用内联:

     public inline fun function(){
         
     }
    
  • 内联的使用细节:在内联函数中不能调用非public修饰的函数

内联实现原理:类似于C++中的define

  • 在编译期做了代码替换

    • 对比使用inline前后反编译得到的 Java代码
  • 在调用处不存在任何的函数开辟,对象开辟;

  • 原函数的Lamda参数依然是转成了Function

    image-20220602232150434

  • 为什么要引入内联:降低性能损耗、减少了在调用出存在对象开辟与调用

    • 原始代码:Kotlin

       package step2
       //函数内联学习
       ​
       //模拟数据库
       const val USER_MAME = "WAsbry"
       const val USER_PWD = "123"
       ​
       //模仿前端作数据的校验:第三个参数为Lamda
       public fun loginAPI(username:String,userpwd:String,responseResulut:(String,Int) -> Unit){
           //做简单校验
           if(username == null || userpwd == null){//TODO 信息为空终止程序
           }
           //调用服务端API
           if(webServiceLoginAPI(username,userpwd)){
               responseResulut("Login success",200)
           }else{
               responseResulut("Login error",444)
           }
       }
       //模仿服务端
       private fun webServiceLoginAPI(name:String,pwd:String) : Boolean{
       //    return if(name == USER_MAME && pwd == USER_PWD)return true else return false
       ​
           return name == USER_MAME && pwd == USER_PWD
       }
       ​
       fun main(){
           loginAPI("WAsbry","123"){msg:String,code:Int->
               println("登录结果为:msg:$msg,code:$code")
           }
       ​
       }
       ​
      
    • 反编译后main函数结果:在调用处会创建对象(instance)

      image-20220602230740850

  • 使用函数内联后:

    • 源代码:

       package step2
       //函数内联学习
       ​
       //模拟数据库
       const val USER_MAME = "WAsbry"
       const val USER_PWD = "123"
       ​
       //模仿前端作数据的校验
       public inline fun  loginAPI(username:String,userpwd:String,responseResulut:(String,Int) -> Unit){
           //做简单校验
           if(username == null || userpwd == null){//TODO 信息为空终止程序
           }
           //调用服务端API
           if(webServiceLoginAPI(username,userpwd)){
               responseResulut("Login success",200)
           }else{
               responseResulut("Login error",444)
           }
       }
       //模仿服务端
       fun webServiceLoginAPI(name:String,pwd:String) : Boolean{
           return name == USER_MAME && pwd == USER_PWD
       }
       fun main(){
           loginAPI("WAsbry","123"){msg:String,code:Int->
               println("登录结果为:msg:$msg,code:$code")
           }
       ​
       }
      
    • 反编译后的 Java文件:不存在对象的使用,但lamda 参数依旧会被编译为接口

      image-20220602231510336

扩招知识:Kotlin中的函数引用

  • 概述:

    • 是什么:函数类型的对象
    • 应用场景:配合inline处理函数参数为Lamda表达式
  • 技巧:可以使用一个单独的对象存放函数引用,在调用处扔进去就行了

     val method = ::verify
    
  • 代码展示:

     package step2
     ​
     //函数引用
     const val NAME = "WAsbry"
     const val PWD = "123"
     ​
     ​
     fun main(){
         login("WAsbry","123",::verify)
     }
     ​
     fun verify(msg: String,code: Int){
         println("登录结果为:msg--->$msg,code--->$code")
     }
     ​
     inline fun login(name: String,pwd: String,responseResult: (name: String,code: Int) ->Unit) {
         if(name == NAME && pwd == PWD){
             responseResult("登录成功",200)
         }else{
             responseResult("登录失败",444)
         }
     }
    

    image-20220602233939356