Kotlin系列(十一)扩展函数详解

  发布日期:   2017-11-07
  最新修改:   2020-03-18
  阅读次数:   33 次

一、前言:

  • 扩展类的函数, 即 Extension Function , 可以在已有类中添加新的方法, 比继承更加简洁和优雅.
  • 函数的扩展其实是一个非常实用的特性。
  • 使用过Swift的小伙伴应该非常熟悉

二、概念

  • 在Kotlin中,允许在不需要继承或使用 Decorator 模式情况下通过一种特殊形式的声明对类进行扩展,实现某一具体功能。
  • 扩展函数是静态解析的,并未对原类增添函数或者属性,也就是说对其本身没有丝毫影响。

三、定义形式

1、扩展函数定义形式:

  • 如果对一个类某一功能并不通用,只有某些特殊场景使用时,可以使用扩展函数,从而让变成灵活多变。

      fun receiverType
        .functionName(params){
          body
      }
  • 函数解析:
    • receiverType:表示函数的接收者,也就是函数扩展的对象
  • functionName:扩展函数的名称
  • params:扩展函数的参数,可以为NULL
  • 扩展函数并没有对原类做修改,而是为被扩展类的对象添加新的函数。

  • 示例代码如下:我们对Int类进行扩展

      fun Int.sayHello(){
          println("hello,I am anjie");
      }
      @Test
      fun test12(){
          var a :Int =1;
          a.sayHello();
      }
  • 运行结果为:hello,I am anjie

  • 可以发现,我们在不影响系统Int类型的基础上对Int

2、扩展函数是静态解析的

  • Kotlin的扩展函数是静态解析的,并不是作为接收者类型的虚拟成员而存在。

  • 静态解析也就意味着调用扩展函数时,具体被调用的的是哪一个函数,由调用函数的对象表达式来决定的,而不是动态的类型决定的。

  • 例子:声明了两个类Person和Student,其中Student继承于Person。

  • 示例代码如下

      open class Person {
      }
    
      class Student : Person() {
    
      }
    
      fun Person.sayHello() {
          println("I am Person")
      }
    
      fun Student.sayHello() {
          println("I am Student")
      }
    
      fun sayGoodby(person: Person) {
          person.sayHello();
          println("BoodBy")
      }
    
      @Test
      fun test13() {
          var student = Student();
          var person = Person();
          student.sayHello();
          person.sayHello();
          sayGoodby(student);
      }
  • 运行结果如下:

      I am Student
      I am Person
      I am Person
      BoodBy
  • 代码解析:

  • 1、我们分别对Person和Student声明扩展函数sayHello(),又声明了sayGoodby()方法,其参数是一个Person对象,在其方法体内,调用了Person的扩展函数。

  • 在调用案例中,创建了一个Student对象student,调用student的扩展函数sayHello,打印了I am Student;创建一个Person对象person,调用扩展函数sayHello,打印了I am Person,说明扩展方法是跟着类走的。

  • 最后我们调用sayGoodby方法,传入的student实例,注意了,我们的Student继承自Person,此时打印的sayHello仍然为Person的扩展方法。

  • 从中我们能够得出一个结论,扩展函数的调用跟着对象类型走,而非实际对象实例。你可以认为是kotlin在编译时为扩展方法指定的类添加的静态方法。

3、类成员函数与类扩展函数函数相同问题

  • 当类的成员函数与扩展函数一摸一样是,是调用扩展函数还是成员函数呢?

  • 带着这样的疑问我们来实践一下

  • 示例代码如下:

      open class Person {
          fun sayHello(){
              println("我是person类成员函数")
          }
      }
    
      class Student : Person() {
    
      }
    
      fun Person.sayHello() {
          println("I am  Person")
      }
    
      fun Student.sayHello() {
          println("I am Student")
      }
    
      fun sayGoodby(person: Person) {
          person.sayHello();
          println("BoodBy")
      }
    
      @Test
      fun test13() {
          var student = Student();
          var person = Person();
          student.sayHello();
          person.sayHello();
          sayGoodby(student);
      }
  • 结果输出如下:

我是person类成员函数 我是person类成员函数 我是person类成员函数 BoodBy

  • 可以看到,当类成员函数与方法成员函数一致时,调用的时类成员函数。

    4、接收者可为NULL

  • 在扩展函数内,我们可以通过this来判断接收者是否为NULL。
  • 这样做的好处是什么呢?假如接收者为NULL,我们也可以通过判断做相对的处理。
      fun Person.sayHello() {

          if (null == this) {
              println("null")
          }
          println("sayHello")
      }

三、扩展属性

  • 扩展属性, 即 Extension Property , 即把某些函数添加为数据, 使用”=”, 直接设置或使用。
  • 通过扩展属性,我们可以像添加扩展函数一样给类添加扩展属性,当然,扩展属性也是静态编译的。所以扩展属性实际上不会向类添加新的成员, 扩展属性的行为只能通过明确给定的取值方法与设值方法来定义。
  • 扩展属性只能被声明为val而不能被声明为var.
  • 示例代码如下:我们给Int类添加一个name属性,访问该属性直接返回Int对应的String形式的值
    val Int.name:String
      get() = this.toString();

     @Test
      fun test14() {
         var a: Int = 100;
         println(a.name)
     } 
  • 运行结果如下:100

   转载规则

《Kotlin系列(十一)扩展函数详解字》GajAngels 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。