为什么需要扩展
为了让一个普通的调用看起来就好像是类的一个方法一样,一般来说用于扩展没有办法修改或者不方便修该或者只是需要临时修改的类。像类的方法一样去调用会更加符合实际逻辑。
扩展方法
简而言之,作为类的扩展方法的函数仍然是一个普通的函数,只是在调用的时候看起来像是类的方法!扩展方法具有以下几点特性:
- 不同于成员方法的权限,和普通函数一样不能访问类的私有属性和方法;
- 扩展方法的调用是静态绑定的,所以没有多态性(扩展方法调用的类的成员方法仍然保持多态性);
- 扩展方法可以被继承;
- 扩展方法可以重载成员方法;
- 扩展方法可以和成员方法冲突(但不要编写这样的代码),不过总是只有成员方法会被调用。
open class C() {}
class D(): C() {}
fun C.foo() = "C"
fun D.foo() = "D"
fun printFoo(c: C) {
print(c.foo())
}
printFoo(D())
以上代码的输出结果为C
.
class C {
fun foo() { println("member") }
}
fun C.foo() { println("extension") }
C().foo()
名称冲突优先成员方法,以上代码输出extension
。
class C {
fun foo() { println("member") }
}
fun C.foo(i: Int) { println("extension") }
如上,没有名称冲突可以实现函数重载。
被扩展的类型可以是nullable
的。可以在函数内部检验对象是否为空,避免重复的null 检查。
扩展属性
语法和扩展方法相同,指定一个接收类即可。扩展属性具有以下限制:
- getter和seter方法的权限同普通外部函数;
- 扩展属性不会修改类本身也就就无法添加字段。所以,扩展属性没有隐藏的幕后字段,不能直接初始化扩展属性;
val Foo.bar = 1 // 错误!试图通过初始化为幕后字段赋值,由于没有幕后字段出错。
将扩展作为其他类的成员
可以将类的成员方法写成其它类的扩展方法,以下例子解释了扩展方法的静态绑定。(注意什么是“dispatch receive”和 “dispatch receive”):
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() // call the extension function
}
}
class C1 : C() {
override fun D.foo() {
println("D.foo in C1")
}
override fun D1.foo() {
println("D1.foo in C1")
}
}
C().caller(D()) // prints "D.foo in C"
C1().caller(D()) // prints "D.foo in C1" - dispatch receiver is resolved virtually
C().caller(D1()) // prints "D.foo in C" - extension receiver is resolved statically
扩展的可见性
扩展不影响其可见性。也就是说,是不是扩展可见性不会发生任何改变。如果原来使用该方法需要import那么作为扩展后无论如何使用扩展还是需要import