一、扩展
Kotlin 能够扩展⼀个类的新功能而无需继承该类或者使用像装饰者这样的设计模式。这通过叫做扩展的特殊声明完成.
1、扩展函数
声明⼀个扩展函数,我们需要用⼀个接收者类型也就是被扩展的类型来作为他的前缀。this 关键字在扩展函数内部对应到接收者对象
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
2.扩展是静态解析的
- 扩展函数是静态分发的,真正的修改他们所扩展的类,仅仅是可以通过该类型的变量用点表达式去调用这个新函数。
- 如果⼀个类定义有⼀个成员函数与⼀个扩展函数,而这两个函数又有相同的接收者类型、相同的名字,并且都适用给定的参数,这种情况总是取成员函数。
- 扩展函数能重载成员函数。
class Example {
fun printFunctionType() {
println("Class method")
}
}
fun Example.printFunctionType() {
println("Extension function")
}
//输出"Class method"
Example().printFunctionType()
3.可空接收者
可以为可空的接收者类型定义扩展
fun Any?.toString(): String {
if (this == null) return "null"
// 空检测之后,“this”会自动转换为⾮空类型,所以下面的 toString()
// 解析为 Any 类的成员函数
return toString()
}
4.扩展属性
- 扩展没有实际的将成员插入类中,因此对扩展属性来说幕后字段是无效的
- 扩展属性不能有初始化器。他们的行为只能由显式提供的 getters/setters 定义。
val <T> List<T>.lastIndex: Int
get() = size - 1
5.伴生对象的扩展
如果⼀个类定义有⼀个伴⽣对象 ,你也可以为伴生对象定义扩展函数与属性。就像伴生对象的常规成员⼀样, 可以只使⽤类名作为限定符来调⽤伴⽣对象的扩展成员:
class MyClass {
companion object {} // 伴⽣对象的名称被省略,将使用 "Companion"
}
fun MyClass.Companion.printCompanion() {
println("companion")
}
fun main() {
MyClass.printCompanion() //该伴生对象的成员可通过只使⽤类名作为限定符来调用
}
6.扩展的作用域
一般在顶层定义扩展,直接在包里,其它包的引用就导包
7.扩展声明为成员
在⼀个类内部你可以为另⼀个类声明扩展。在这样的扩展内部,有多个隐式接收者。其中的对象成员可以无需通过限定符访问。
扩展声明所在的类的实例称为分发接收者,扩展方法调用所在的接收者类型的实例称为扩展接收者 。
对于分发接收者与扩展接收者的成员名字冲突的情况,扩展接收者优先。要引用分发接收者的成员你可以使用限定的 this语法。
//扩展接收者
class Host(val hostname: String) {
fun printHostname() {
print(hostname)
}
}
//分发接收者
class Connection(val host: Host, val port: Int) {
fun printPort() {
print(port)
}
fun Host.printConnectionString() {
printHostname() // 调⽤ Host.printHostname()
print(":")
printPort() // 调⽤ Connection.printPort()
}
fun connect() {
host.printConnectionString() // 调⽤扩展函数
}
//对于分发接收者与扩展接收者的成员名字冲突的情况,扩展接收者优先。要引⽤分发接收者的成员你可以使⽤限定的 this 语法。
fun Host.getConnectionString() {
toString() // 调⽤ Host.toString()
this@Connection.toString() // 调⽤ Connection.toString()
}
fun connectString(){
host.getConnectionString()
}
}
声明为成员的扩展可以声明为 open 并在子类中覆盖。这意味着这些函数的分发对于分发接收者类型是虚拟的,但对于扩展接收者类型是静态的。
8.关于可见性的说明
扩展的可见性与相同作用域内声明的其他实体的可见性相同。
- 在文件顶层声明的扩展可以访问同⼀文件中的其他 private 顶层声明;
- 如果扩展是在其接收者类型外部声明的,那么该扩展不能访问接收者的 private 成员。
网友评论