在 Java 中,想要扩展类的功能,可是又不想直接改原来的类时,通常会采用继承、组合(装饰者模式)等方式来实现。而 Kotlin 中支持对类的属性和函数进行扩展,在类外增长原来类的属性和函数,能够方便地实如今原来的类上添加新功能。后端
函数扩展的格式为:bash
fun <类名>.<扩展函数名>([参数列表])<:返回类型>{
}
复制代码
在 Android 开发中,咱们常常须要在 Activity 中弹出 Toast,每次要写:Toast.makeText(this, "text", Toast.LENGTH_SHORT).show();
这么一长串很累,一般都会封装一个工具类来简化一下调用: ToastUtils.makeToast("text");
。函数
在 Kotlin 中,有了扩展函数,咱们能够更加方便优雅地弹 Toast,工具
在一个扩展文件中,对 Context 类加一个扩展函数,由于 Activity 是 Context 的子类,也能够直接调用。ui
fun Context.showToast(content: String) {
Toast.makeText(this, content, Toast.LENGTH_SHORT).show()
}
复制代码
这样在 Activity 中咱们就能够这样来弹 Toast:this
button.setOnClickListener{
showToast("text")
}
复制代码
是否是很是方便简洁?spa
在扩展函数中,可使用 this
关键字指代调用这个函数的对象。code
扩展函数是静态解析的对象
扩展函数时静态解析的,具体调用哪个类的函数,由调用函数的表达式类型决定,而不是由表达式运行时的动态类型决定。继承
open class Shape
class Rectangle: Shape()
fun Shape.getName() = "Shape"
fun Rectangle.getName() = "Rectangle"
fun printClassName(s: Shape) { //类型是Shape
println(s.getName())
}
printClassName(Rectangle())
//运行结果
Shape
复制代码
和成员函数重名
若是扩展函数和类的成员函数一致时,优先调用成员函数。
class C {
fun foo() { println("成员函数") }
}
fun C.foo() { println("扩展函数") }
fun main(){
var c = C()
c.foo()
}
//运行结果
成员函数
复制代码
空对象的扩展
在扩展函数内, 能够经过 this == null
来判断接收者是否为 null。这样,即便接收者为 null,也能够调用扩展函数。
fun Any?.toString(): String {
if (this == null) return "null"
// 空检测以后,“this”会自动转换为非空类型,因此下面的 toString()
// 解析为 Any 类的成员函数
return toString()
}
fun main(){
var t = null
println(t.toString())
}
//运行结果
null
复制代码
Java 中调用扩展函数
经过文件名+Kt.函数名(扩展类的对象,完整的其余参数)
来在 Java 中调用扩展函数(至关于调用工具类的静态方法)。
例如以前的 Toast 示例,该扩展函数写在 Utils.kt 文件下,则在 Java 代码中应该这样调用这个函数。
UtilsKt.showToast(MainActivity.this, "Hello");
复制代码
Kotlin 也支持对属性进行扩展。
val <T> List<T>. lastIndex: Int
get() = size - 1
复制代码
因为扩展没有实际的将成员插入类中,所以对扩展属性来讲后端变量
是无效的。这就是为何扩展属性不能有初始化器。他们的行为只能由显式提供的 getters/setters 定义。
扩展函数只能被声明为 val
。
能够给类的伴生对象定义扩展函数和属性。
伴生对象经过类名.
的形式调用伴生对象,伴生对象声明的扩展函数,经过用类名限定符来调用:
class MyClass {
companion object { } // 将被称为 "Companion"
}
fun MyClass.Companion.foo() {
println("伴随对象的扩展函数")
}
val MyClass.Companion.no: Int
get() = 10
fun main(args: Array<String>) {
println("no:${MyClass.no}")
MyClass.foo()
}
//运行结果
no:10
伴随对象的扩展函数
复制代码