Kotlin可以在不继承一个类的前提下去扩展一个类的新功能,支持扩展函数和扩展属性。扩展函数一般应用于第三方的sdk,或者是你没有办法控制的一些类,可以对这个类添加一些成员变量或者成员方法。
扩展函数
声明一个扩展函数,需要用一个接受这类型也就是被扩展的属性来作为他的前缀。下面代码为File添加一个readText的扩展函数
fun File.readText(charset: Charset = Charsets.UTF_8):String = readBytes().toString(charset)
val file = File("build.gradle")
println(file.readText())
扩展函数是静态解析的
扩展函数不能真正的去修改他们所扩展的类。通过定义一个扩展,并没有在扩展的类中插入新成员,仅仅是可以通过该类去调用这个新函数。扩展函数是静态的给类去添加的,不具备运行时的多态的。下面的代码
open class Animal
class Dog : Animal()
fun Animal.name() = "animal"
fun Dog.name() = "dog"
fun Animal.printName(anim:Animal){
println(anim.name())
}
fun main(args: Array<String>){
Dog().printName(Dog())
}
运行main函数最后输出的是
animal
扩展函数会被编译成public static 类型的函数,在编译后扩展函数会多加一个参数,这个参数是扩展的那个类的对象,下面是编译后的代码
@NotNull
public static final String name(@NotNull Animal $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
return "animal";
}
@NotNull
public static final String name(@NotNull Dog $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
return "dog";
}
public static final void printName(@NotNull Animal $receiver, @NotNull Animal anim) {
Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
Intrinsics.checkParameterIsNotNull(anim, "anim");
String var2 = name(anim);
System.out.println(var2);
}
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
printName((Animal)(new Dog()), (Animal)(new Dog()));
}
Dog是被强转成了Animal,实际上在调用的时候调用的是Animal的 name()
如果一个类定义了一个成员函数与一个扩展函数,而这两个函数又有相同的接受者类型,相同的名字,都适用与给定的参数,这种情况调用成员函数。例如:
class C {
fun foo() { println("member") }
}
fun C.foo() { println("extension") }
调用C().foo()输出“member”
扩展函数可以重载成员函数
class C {
fun foo() { println("member") }
}
fun C.foo(i: Int) { println("extension") }
可空接受者
可以为可空的接受者类型定义扩展,这样可以使用可能为空的对象 调用扩展函数
fun Any?.toString(): String {
if (this == null) return "null"
// 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
// 解析为 Any 类的成员函数
return toString()
}
扩展属性
kotlin支持扩展属性,由于扩展并没有实际将成员插入类中, 只能通过getters/setters操作
val <T> List<T>.lastIndex: Int
get() = size - 1
val Foo.bar = 1 // 错误:扩展属性不能有初始化器
伴生对象也可以扩展
class MyClass {
companion object { } // 将被称为 "Companion"
}
fun MyClass.Companion.foo() { …… }
//就像伴生对象的其他普通成员,只需用类名作为限定符去调用他们
MyClass.foo()
分发接受者 扩展接受者
扩展声明所在的类的实例称为 分发接收者 ;扩展方法调用所在的接收者类型的实例称为 扩展接收者 。对于分发接收者与扩展接收者的成员名字冲突的情况,扩展接收者优先。
声明为成员的扩展可以声明为 open
并在子类中覆盖。这意味着这些函数的分发对于分发接收者类型是虚拟的,但对于扩展接收者类型是静态的。
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")
}
}
fun main() {
C().caller(D()) // 输出 "D.foo in C"
C1().caller(D()) // 输出 "D.foo in C1" —— 分发接收者虚拟解析
C().caller(D1()) // 输出 "D.foo in C" —— 扩展接收者静态解析
}