一、扩展函数和扩展属性
1.1、扩展函数
扩展函数用于为一个类增加一种新的行为,这是为缺少有用函数的类进行扩展的途径。扩展函数的用途就类似于在 Java 中实现的静态工具方法。而在 Kotlin 中使用扩展函数的一个优势就是我们不需要在调用方法的时候把整个对象当作参数传入,扩展函数表现得就像是属于这个类本身的一样,可以使用 this 关键字并直接调用其所有 public 方法
扩展函数并不允许你打破它的封装性,和在类内部定义的方法不同的是,扩展函数不能访问私有的或是受保护的成员
扩展函数的声明
//为 String 类声明一个扩展函数 lastChar() ,用于返回字符串的最后一个字符
//get方法是 String 类的内部方法,length 是 String 类的内部成员变量,在此处可以直接调用
fun String.lastChar() = get(length - 1)
//为 Int 类声明一个扩展函数 doubleValue() ,用于返回其两倍值
//this 关键字代表了 Int 值本身
fun Int.doubleValue() = this * 2
之后,我们就可以像调用类本身内部声明的方法一样,直接调用扩展函数
fun main(args: Array<String>) {
val name = "leavesC"
println("$name lastChar is: " + name.lastChar())
val age = 24
println("$age doubleValue is: " + age.doubleValue())
}
1.2、扩展属性
扩展函数也可以用于属性
//扩展函数也可以用于属性
//为 String 类新增一个属性值 customLen
var String.customLen: Int
get() = length
set(value) {
println("set")
}
fun main(args: Array<String>) {
val name = "leavesC"
println(name.customLen)
name.customLen = 10
println(name.customLen)
//7
//set
//7
}
1.3、不可重写的扩展函数
看以下例子,子类 Button 重写了父类 View 的 click() 函数,此时如果声明一个 View 变量,并赋值为 Button 类型的对象,调用的 click() 函数将是 Button 类重写的方法
fun main(args: Array<String>) {
val view: View = Button()
view.click() //Button clicked
}
open class View {
open fun click() = println("View clicked")
}
class Button : View() {
override fun click() = println("Button clicked")
}
对于扩展函数来说,与以上的例子却不一样。如果基类和子类都分别定义了一个同名的扩展函数,此时要调用哪个扩展函数是由变量的静态类型来决定的,而非这个变量的运行时类型
fun main(args: Array<String>) {
val view: View = Button()
view.longClick() //View longClicked
}
open class View {
open fun click() = println("View clicked")
}
class Button : View() {
override fun click() = println("Button clicked")
}
fun View.longClick() = println("View longClicked")
fun Button.longClick() = println("Button longClicked")
此外,如果一个类的成员函数和扩展函数有相同的签名,成员函数会被优先使用
扩展函数并不是真正地修改了原来的类,其底层其实是以静态导入的方式来实现的。扩展函数可以被声明在任何一个文件中,因此有个通用的实践是把一系列有关的函数放在一个新建的文件里
需要注意的是,扩展函数不会自动地在整个项目范围内生效,如果需要使用到扩展函数,需要进行导入
1.4、可空接收者
可以为可空的接收者类型定义扩展,即使接受者为 null,使得开发者在调用扩展函数前不必进行判空操作,且可以通过 this == null
来检查接收者是否为空
fun main(args: Array<String>) {
var name: String? = null
name.check() //this == null
name = "leavesC"
name.check() //this != null
}
fun String?.check() {
if (this == null) {
println("this == null")
return
}
println("this != null")
}