理论上讲,扩展函数非常简单,它就是一个类的成员函数,不过定义在类的外面。为了方便阐释,让我们添加一个方法,来计算一个字符串的最后一个字符:
// 扩展函数,它就是一个类的成员函数,不过是定义在类的外面
package strings
fun String.lastChar(): Char = this.get(this.length - 1)
这个类的名称被称为接收者类型;用来调用这个扩展函数的那个对象,叫接收者对象
可以像调用类的普通成员函数一样去调用这个函数
》》》
println("Kotlin".lastChar())
在这个例子中,String就是接收者类型,“Kotlin”就是接收者对象。
从某种意义上说,你已经为String类添加了自己的方法
在这个扩展函数中,可以像其他成员函数一样用this。而且也可以像普通的成员函数一样,省略它。
fun String.lastChar(): Char = this.get(length - 1)
在扩展函数中,可以直接访问到被扩展的类的其他方法和属性,就好像是在这个类自己的方法中访问它们一样,注意,扩展函数并不允许你打破它的封装性。和在类内部定义的方法不同的是,扩展函数不能访问私有的或者是受保护的成员
3.3.1 导入和扩展函数
对于你定义的一个扩展函数,它不会自动地在整个项目生效,如果要使用它你需要导入。Kotlin允许用和导入类一样的语法来导入单个的函数:
import strings.lastChar
val c = "Kotlin“.lastChar()
当然用 * 来导入也是可以的
import strings.*
val c = "Kotlin“.lastChar()
可以使用关键字“as”来修改导入的类火灾函数的名称:
import strings.lastChar as last
>>>
println("Kotlin".last())
在不同的包下有重名的函数时,在导入时给它重新命名就显得很有必要
3.3.2 从Java中调用扩展函数
实质上扩展函数就是静态函数,它把调用对象作为了它的第一个参数。调用扩展函数,不会创建适配的对象或者任何运行时的额外损耗。
这使得从Java中调用Kotlin的扩展函数变得非常简单:调用这个静态函数,然后把接收者对象作为第一个参数传进去即可。和其他顶层函数一样,包括这个函数的Java类的名称,是由这个函数声明的文件名称决定的。假设它声明在一个叫作StringUtil.kt文件中:
char c = StringUtilKt.lastChar("Java")
这个扩展函数被声明为顶层函数,所以,它将会被编译为一个静态函数。
3.3.3 作为扩展函数的工具函数
package strings
fun <T> Collection<T>.joinToString2( separator: String = ";", prefix: String = "[", postfix: String = "]"): String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) {
if (index > 0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
使用的时候
import strings.joinToString2
3.3.4 不可重写的扩展函数
应为扩展函数是声明在类外部的,转换为java其实就是静态函数,静态函数是属于类,不能被重写,故而不能体现多态.
3.3.5 扩展属性
扩展属性提供一种方法,用来扩展类的API,可以用来访问属性,用的是属性语法而不是函数的语法。尽管它们被视为属性,但它们可以没有任何状态,因为没有合适的地方来存储它,不可能给现有的Java对象的实例添加额外的字段。但有时短语法仍然是便于使用的。
上一节我们定义了lastChar函数,现在我们定义一个lastChar属性
package strings
val String.lastChar: Char
get() = get(this.length - 1)
可以看到,可扩展函数一样,扩展属性也像接收者的一个普通的成员属性一样。这里,必须定义getter函数,因为没有支持字段,因此没有默认getter的实现。同理,初始化也不可以:因为没有地方储存初始值。
声明一个StringBuilder可变得扩展属性,可以置为var
package strings
var StringBuilder.lastChar: Char
get() = get(this.length - 1)
set(value: Char) {
this.setCharAt(length - 1, value)
}
>>>
import strings.lastChar as last
val sb = StringBuilder("Kotlin?")
println(sb.last)
sb.last = '!'
println(sb)
注意,当你需要从Java中访问扩展属性的时候,应该显式的调用它的getter函数
StringUtilKt.getLastChar("Java")
《参考Kotlin实战》