前言
kotlin同C#和Gson类似,能够扩展一个类的心的功能而无需继承该类或使用像对象修饰者这样的任何类型的设计模式,这个通过叫扩展的特殊声明完成,kotlin 支持扩展函数和扩展属性。
扩展函数
声明一个扩展函数,我们需要用一个接收者类型也就是被扩展的类型来作为他的前缀,例如`
import java.lang.StringBuilder
fun main(args: Array<String>) {
val name = "栾小黑"
println(name.MyAppend("超级厉害"))
}
/***
* 对String这个类进行扩展 在原本的字符串后边拼接字符串
* name 拼接的字符串内容
*/
fun String.MyAppend(name: String): String {
val stringBuilder = StringBuilder()
stringBuilder.append(this)
stringBuilder.append(name)
val result = stringBuilder.toString()
return result
}
扩展是静态解析的
扩展不能真正的修改他们的扩展类。通过定义一个扩展,你并没有在类中插入新的成员,仅仅是可以通过该类型的变量使用点的表达式调用这个函数。
我们像强调得失扩展函数是静态分发的,即他们不是根据接收者类型的虚方法。这意味着调用的扩展函数是由函数调用所在的表达式的类型决定的,而不是由表达式运行的结果决定的
open class C
class D: C()
fun C.foo() = "c"
fun D.foo() = "d"
fun printFoo(c: C) {
println(c.foo())
}
printFoo(D())
这个例子会输出c 因为调用的扩展函数只取决于参数c的声明类型,该类型是C类
备注:如果一个类定义有一个成员函数与一个扩展函数,而这两个函数又有相同的接收者类型、相同的名字,都适用给定的参数,这种情况总是取成员函数。
//为String类添加一个扩展方法get()无论什么时候都会返回一个字符c
fun String.get(index: Int): Char {
return 'c'
}
fun main(args: Array<String>) {
val name = "栾小黑"
println( name.get(2))
}
此段代码运行的结果是 “黑”说明调用的是String类自己的get方法,而不是我们写的扩展方法。
可空接收者
注意可以为可空的接受者类型定义扩展。这样的扩展可以在对象变量上调用,即使他的值是null,并且可以在函数体内部检测 this==null,这能让你在没有检测null的时候调用kotlin的toString(): 检测发生在扩展函数的内部
fun Any?.toString(): String {
if (this == null) return "null"
return this.toString()
}
fun main(args: Array<String>) {
val nameTwo:String? = "hello world"
val nameTwo:String? = null
println(nameTwo.toString())
println(nameThree.toString())
}
该程序会输出 hello world,null
扩展属性
与函数类似,kotlin 支持扩展属性:
val <T> List<T>.lastIndex:Int get() = size-1
注意:由于扩展没有实际的将成员插入类中,因此对扩展属性来说幕后字段是无效的。这就是为什么扩展属性不能有初始化器。他们的行为只能由显式提供的 getters/setters 定义。
声明属性的完整的语法是
var [:] [=<property_initializer>]
[ getter方法 ]
[ settter方法]
伴生对象的扩展
如果一个类又一个伴生对象,你也可以为伴生对象定义扩展函数的属性:
class MyClass{
companion object{ } // 伴生对象
}
fun MyClass.Companion.foo(){...}
就像伴生对象的其他普通成员一样,只需要用类名做限定符去调用他们