Kotlin for android学习三:扩展函数与扩展属性

前言

kotlin官网 (中文版)和kotlin教程学习教程的笔记。

一、扩展函数

  1. 直接举个例子吧
fun  MutableList.swap(index1: Int, index2: Int) { 
  val tmp = this[index1] // this关键字指代接收者对象,这里指代list实例,
  this[index1] = this[index2]
  this[index2] = tmp
}

  var list = mutableListOf(1, 2, 3)
  list.swap(0, 2)//对任意一个 MutableList 对象调用这个扩展函数
  println(list.toString()) //输出结果为[3, 2, 1]
  1. 扩展函数是静态解析的!!!
    扩展函数是静态解析的!!!
    扩展函数是静态解析的!!!
    重要的话说三遍,意思如下:

调用扩展函数时, 具体被调用的函数是哪一个, 是通过调用函数的对象表达式的类型来决定的, 而不是 在运行时刻表达式动态计算的最终结果类型决定的

不太清晰,请看下例:

open class C
class D: C()
fun C.foo() = "c"
fun D.foo() = "d"
fun printFoo(c: C) {
  println(c.foo()) 
}
printFoo(D()) //输出c

那么,如果类中存在成员函数, 同时又在同一个类上定义了同名同参数的扩展函数会怎样?这种情况下总是会优先使用成员函数

class C {
fun foo() { println("member") }
}
fun C.foo() { println("extension") }

c.foo() // 输出member
  1. 将扩展定义为成员,看下例:
 class C
    class D {
        fun C.foo() {
            println(toString())
            println([email protected]())
        }
        fun call(c: C) {
            c.foo()
        }
    }
        D().call(C())

输出结果如下:



这里,我们可以看到,默认调用了扩展方法定义的类的方法。

引入一个概念:

  1. 在类的内部, 你可以为另一个类定义扩展. 在这类扩展中, 存在多个 隐含接受者(implicit receiver) - 这些隐 含接收者的成员可以不使用限定符直接访问.
  2. 扩展方法的定义所在的类的实例, 称为_派发接受者(dispatch receiver),
    扩展方法的目标类型的实例, 称为 _扩展接受者(extension receiver) .
  3. 当派发接受者与扩展接受者的成员名称发生冲突时, 扩展接受者的成员将会被优先使用.

这个例子中,C为扩展接受者,D为派发接受者。

  1. 小试牛刀
open class D
    class D1 : D()
    open class C {
        open fun D.foo() {
            println("D.foo in C")
        }

        open fun D1.foo() {
            println("D1.foo in C")
        }

        fun caller(d: D) {
            d.foo() // 调用扩展函数
        }
    }

    class C1 : C() {
        override fun D.foo() {
            println("D.foo in C1")
        }

        override fun D1.foo() {
            println("D1.foo in C1")
        }
    }
//-----看好题了么?-测试开始---
     C().caller(D())  //输出??
     C1().caller(D())  //输出??
     C().caller(D1()) //输出??

答案揭晓:

C().caller(D()) // 打印结果为 "D.foo in C"
C1().caller(D()) // 打印结果为 "D.foo in C1" - 派发接受者的解析过程是虚拟的 
C().caller(D1()) // 打印结果为 "D.foo in C" - 扩展接受者的解析过程是静态的

你答对了么?

二、扩展属性

 val String.upper
        get() = toUpperCase()

   var s = "aBcDefg"
        println(s.upper)//输出ABCDEFG

扩展属性不应该初始化,因为扩展属性没有后端域变量,在上一节中我们说“初始化给定的值将直接写入后端域变量中”,因此不能够初始化。
那么为何没有后端域变量呢?由于扩展属性实际上不会向类添加新的成员, 因此无法让一个扩展属性拥有一个 后端域变量

三、对同伴对象(Companion Object)的扩展

什么是同伴对象?由于Kotlin 的类没有静态方法, 大多数情况下, 建议使用包级函数替代, 或者使用同伴对象,达到静态方法效果

package com.example.demo
 class User { 
   companion object { //同伴对象
        fun foo(){  }
   }
}
fun pfoo(){} //包级函数

User.foo() //这样,调用的时候就不需要使用对象调用了
  pfoo()

对这个同伴对象定义扩展函数和扩展属性:

class User {
    companion object { //同伴对象
        fun foo() {}
    }
}
fun pfoo() {} //包级函数

fun User.Companion.cfoo() {} // 对这个同伴对象定义扩展函数
val User.Companion.getData: String // 对这个同伴对象定义扩展属性
    get() = toString()

User.foo()
pfoo()
User.cfoo()//与同伴对象的常规成员一样, 可以只使用类名限定符来调用这些扩展函数和扩展属性
println(User.getData) //输出com.example.demo.User$Companion@9bdf2f3

四、使用扩展的动机

扩展函数数是指在一个类上增加一种新的行为,甚至我们没有这个类代码的访问权限。这是一个在缺少有用函数的类上扩展的方法。在Java中,通常会实现很多带有 static方法的工具类。Kotlin中扩展函数的一个优势是我们不需要在调用方法的时候 把整个对象当作参数传入
总而言之就是,解决**Utils.的麻烦,解决静态导入无法使用代码补全功能的麻烦

你可能感兴趣的:(Kotlin for android学习三:扩展函数与扩展属性)