阅读 149

Kotlin原理详析之拓展函数

kotlin中的扩展函数,实际上是在自己的类中添加了一个static final方法,将需要扩展的类,在使用的时候作为第一个参数传入方法中,然后使用,这篇文章主要给大家介绍了关于Kotlin原理详析之拓展函数的相关资料,需要的朋友可以参考下

目录
  • 原理

  • 限制

    • 不能访问私有成员

    • 拓展函数不能实现多态

    • 成员函数优先级高,拓展函数不能实现重写

  • 为什么要使用Kotlin中的扩展函数

    • 总结

      原理

      拓展函数是kotlin里一个比较常用的特性,例如我们可以给Context拓展一个toast方法:

      1
      2
      3
      4
      5
      6
      7
      8
      // MainActivity.kt
      fun Context.toast(msg: String) {
          Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
      }
       
      private fun foo(context: Context) {
          context.toast("hello world")
      }

      它的原理其实很简单,就是生成了一个toast方法。拓展函数的this指针实际上是这个生成方法的第一个参数:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      /* compiled from: MainActivity.kt */
      public final class MainActivityKt {
       
          public static final void toast(Context $this$toast, String msg) {
              //参数判空
              ...
       
              // 拓展函数代码
              Toast.makeText($this$toast, msg, 0).show();
          }
      }

      所以这个this指针实际上是由函数调用的地方传入的对象引用:

      1
      2
      3
      private final void foo(Context context) {
          MainActivityKt.toast(context, "hello world");
      }

      限制

      知道了拓展函数的实现原理之后我们就能从原理去理解拓展函数的种种限制.

      不能访问私有成员

      由于编译成java之后,生成的拓展方法实际是靠第一个参数出入对象引用,然后使用这个对象引用去调用对象的方法。因此我们并没有权限在拓展函数里面调用私有方法:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      class TestClass {
          fun publicFun() {}
          private fun privateFun() {}
      }
       
      fun TestClass.extFun() {
          publicFun() // 正确,可以调用公有方法
       
          privateFun() // 错误,不能调用私有方法
      }

      拓展函数不能实现多态

      由于拓展函数并不是真的给类增加一个成员函数,所以父类和子类的同名拓展函数并没有多态的特性。

      例如我们为父类和子类拓展同一个foo()函数:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      open class Parent
      class Child : Parent()
       
      fun Parent.foo() {
          println("parent")
      }
       
      fun Child.foo() {
          println("child")
      }

      然后只要将子类转换成父类,调用的拓展函数就是父类的拓展函数:

      1
      2
      3
      4
      5
      6
      7
      val child = Child()
      child.foo()
      (child as Parent).foo()
       
      // 输出:
      // child
      // parent

      成员函数优先级高,拓展函数不能实现重写

      当拓展函数与类本身或者父类的成员函数相同,在实际调用的时候会优先调用成员函数,并不会出现类似重写的效果.

      例如我们为一个类编写了一个与成员函数相同的拓展函数,实际优先调用类成员函数:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      open class Parent {
          fun foo() {
              println("foo")
          }
      }
       
      fun Parent.foo() {
          println("parent")
      }
       
      Parent().foo()
       
      // 输出:
      // foo

      就算是为子类编写了一个与父类成员函数相同的拓展函数,也会优先调用父类的成员函数:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      open class Parent {
          fun foo() {
              println("foo")
          }
      }
       
      class Child : Parent()
       
      fun Child.foo() {
          println("child")
      }
       
      Child().foo()
       
      // 输出:
      // foo
      关闭

      为什么要使用Kotlin中的扩展函数

      我们都知道在Koltin这门语言可以与Java有非常好的互操作性,所以扩展函数这个新特性可以很平滑与现有Java代码集成。甚至纯Kotlin的项目都可以基于Java库,甚至Android中的一些框架库,第三方库来构建。扩展函数非常适合Kotlin和Java语言混合开发模式。在很多公司一些比较稳定良好的库都是Java写,也完全没必要去用Kotlin语言重写。但是想要扩展库的接口和功能,这时候扩展函数可能就会派上用场。使用Kotlin的扩展函数还有一个好处就是没有副作用,不会对原有库代码或功能产生影响。先来看下扩展函数长啥样

      给TextView设置加粗简单的例子

      1
      2
      3
      4
      5
      6
      //扩展函数定义
      fun TextView.isBold() = this.apply {
          paint.isFakeBoldText = true
      }
      //扩展函数调用
      activity.find<TextView>(R.id.course_comment_tv_score).isBold()

      总结

      到此这篇关于Kotlin原理详析之拓展函数的文章就介绍到这了

      原文链接:https://blog.islinjw.cn/2022/01/25/Kotlin原理-拓展函数/


      文章分类
      代码人生
      版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
      相关推荐