前言
kotlin官网 (中文版)和kotlin教程学习教程的笔记。
一、扩展函数
- 直接举个例子吧
fun <T> MutableList<T>.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<T> 对象调用这个扩展函数
println(list.toString()) //输出结果为[3, 2, 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
- 将扩展定义为成员,看下例:
class C
class D {
fun C.foo() {
println(toString())
println(this@D.toString())
}
fun call(c: C) {
c.foo()
}
}
D().call(C())
输出结果如下:
这里,我们可以看到,默认调用了扩展方法定义的类的方法。
引入一个概念:
- 在类的内部, 你可以为另一个类定义扩展. 在这类扩展中, 存在多个 隐含接受者(implicit receiver) - 这些隐 含接收者的成员可以不使用限定符直接访问.
- 扩展方法的定义所在的类的实例, 称为_派发接受者(dispatch receiver),
扩展方法的目标类型的实例, 称为 _扩展接受者(extension receiver) .- 当派发接受者与扩展接受者的成员名称发生冲突时, 扩展接受者的成员将会被优先使用.
这个例子中,C为扩展接受者,D为派发接受者。
- 小试牛刀
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.的麻烦,解决静态导入无法使用代码补全功能的麻烦
网友评论