美文网首页
Kotlin函数关键字inline内联函数原理

Kotlin函数关键字inline内联函数原理

作者: ModestStorm | 来源:发表于2022-09-27 13:15 被阅读0次

    前言

    Kotlin扩展函数为我们提供了方便的开发调用,不用通过继承或者装饰者模式来实现功能的扩展,它的内部原理其实是通过封装了public static final method(调用者对象作为参数)方法,效率上并没有什么提升。

    扩展函数定义

    1.在ExtentKotlin.kt中定义扩展函数:

     fun String.printlnHaHa(){
        var result = "haha$this"
        println(result)
    }
    

    2.外部使用扩展函数:

    open class MediaPlayer(var path:String) {
         fun play(path:String){
            "aa".printlnHaHa()
        }
    }
    

    3.查看字节码生成,反编译为java类
    AS -> tools -> Kotlin -> show Kotlin byte code -> Decompile

    4.ExtentKotlin.kt中的扩展函数反编译

    public final class ExtentKotlinKt {
       public static final void printlnHaHa(@NotNull String $this$printlnHaHa) {
          Intrinsics.checkParameterIsNotNull($this$printlnHaHa, "$this$printlnHaHa");
          String result = "haha" + $this$printlnHaHa;
          System.out.println(result);
       }
    }
    

    可以看到扩展函数语法糖背后的实现原理
    1.生成了一个final类ExtentKotlinKt
    2.将扩展函数转变为了public static final 类型的方法,方法参数是类扩展函数类型的参数,方法内部使用这个函数做了操作处理
    3.根据分析从而得知其他地方就是通过调用ExtentKotlinKt的static final方法实现的调用。

    1. 扩展函数的外部调用
    public class MediaPlayer {
       @NotNull
       private String path;
    
       public final void play(@NotNull String path) {
          Intrinsics.checkParameterIsNotNull(path, "path");
          // 在这里调用了外部扩展类的静态方法,并将调用对象传递给扩展函数了
          ExtentKotlinKt.printlnHaHa("aa");
       }
    
       @NotNull
       public final String getPath() {
          return this.path;
       }
    
       public final void setPath(@NotNull String var1) {
          Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
          this.path = var1;
       }
    
       public MediaPlayer(@NotNull String path) {
          Intrinsics.checkParameterIsNotNull(path, "path");
          super();
          this.path = path;
       }
    }
    

    inline关键字原理

    还以上面的例子分析扩展函数,在扩展函数加上inline关键字进行修饰,查看反编译后的效果

    1.inline关键字修饰扩展函数

     inline fun String.printlnHaHa(){
        var result = "haha$this"
        println(result)
    }
    

    2.查看反编译后对应的java文件

    public final class ExtentKotlinKt {
       public static final void printlnHaHa(@NotNull String $this$printlnHaHa) {
          int $i$f$printlnHaHa = 0;
          Intrinsics.checkParameterIsNotNull($this$printlnHaHa, "$this$printlnHaHa");
          String result = "haha" + $this$printlnHaHa;
          System.out.println(result);
       }
    }
    

    与扩展函数的实现一样并没有什么改变,还是public static final方法

    3.外部类使用inline关键字的扩展函数

    open class MediaPlayer(var path:String) {
         fun play(path:String){
            "aa".printlnHaHa()
        }
    }
    

    4.反编译外部类

    public class MediaPlayer {
       @NotNull
       private String path;
    
       public final void play(@NotNull String path) {
          Intrinsics.checkParameterIsNotNull(path, "path");
        /*
        这里的调用发生了改变,不再是直接调用
        ExtentKotlinKt.printlnHaHa("aa"), 
        而是直接将方法体中的内容复制了一遍执行,
        这么做可以减少方法的查找和调用,效率上有所提高了
        */
          String $this$printlnHaHa$iv = "aa";
          int $i$f$printlnHaHa = false;
          String result$iv = "haha" + $this$printlnHaHa$iv;
          System.out.println(result$iv);
       }
    
       @NotNull
       public final String getPath() {
          return this.path;
       }
    
       public final void setPath(@NotNull String var1) {
          Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
          this.path = var1;
       }
    
       public MediaPlayer(@NotNull String path) {
          Intrinsics.checkParameterIsNotNull(path, "path");
          super();
          this.path = path;
       }
    

    总结

    inline内联函数会复制一遍函数内部方法体的实现,这样会让使用处的代码膨胀. 所以官方极力建议, 内联函数的代码不建议超过 3 行. 控制在 1~3 行代码是最佳的。

    相关文章

      网友评论

          本文标题:Kotlin函数关键字inline内联函数原理

          本文链接:https://www.haomeiwen.com/subject/cjfvortx.html