扩展函数和扩展属性都会被编译成一个方法,这个方法的第一个参数就是扩展的接收者,然后才是其它各个参数。对于扩展属性来说 ,因为编译后这个属性并不存在,所以不能像一般的类属性那样对它进行初始化,而是要自定义 getter 和 setter 来访问它。
一、扩展函数
不修改源文件的情况下,为一个类扩展新功能无需继承重写,反编译成java是生成了对应的静态方法,并没有真正的修改了类。一个类只定义框架,工具函数可以通过外部扩展一点点地添加,尽量不改动原有的类。
- fun 类名.方法名(参数列表) : 返回值类型 { 方法体 }
- 扩展函数不允许打破封装,无法访问类中 private 和 protected 成员。
- 扩展函数无法被覆盖,子父类都添加了同样的函数,子类执行自己的。
- 一个类的扩展函数可以在同包目录下直接调用,出了这个范围需要导包使用。(不必像 Java 为了定义一个方法而专门创建工具类或使用装饰者模式,可以把公共函数写到一个 .kt 文件中,通过 import 导入就可以使用了)。
- 写在成员函数位置上时所属于该类,写在顶层函数位置上时所属于该包。
- 不要因为限制可见性将扩展函数定义为成员函数,而是使用可见性修饰符。private 修饰的顶层扩展函数只在该 kt 文件内可访问。
- 建议向哪个类中添加扩展函数,就定义一个同名的文件(如StringExt.kt),这样便于你以后查找。当然也是可以定义在任何一个现有类当中的,并不一定非要创建新文件。通常来说,最好将它定义成顶层方法,这样可以让扩展函数拥有全局的访问域。
举例:为String类添加获取字符个数的扩展函数。
fun String.getCharCount() :Int{
var count = 0
for (it in this) {
count++
}
return count
}
println("123456".getCharCount()) //打印:6
为超类定义扩展函数
为父类定义的扩展函数,所有子类都可以调用。
fun Any.printSelf() {
println(this)
}
"hello".printSelf()
123.printSelf()
为泛型定义扩展函数
可以支持任何类型的接收者。一般用于链式调用,因此返回值类型为接收者类型。
fun <T> T.printSelf(): T {
println(this)
return this
}
"hello".printSelf().length
123.printSelf() + 1
为可空类型定义扩展函数
接收者可以为空,因此需要对 this == null 做判断。
//为可空类型定义的扩展函数
fun String?.printSelf1() {
if(this == null) {
return
}
println(this)
}
//为非空类型定义的扩展函数
fun String.printSelf2() {
println(this)
}
fun main() {
val str1: String = "123"
val str2: String? = null
str1.printSelf1() //打印:123
str1.printSelf2() //打印:123
str2.printSelf1() //直接return掉了
str2?.printSelf2() //为null不会调用
}
二、扩展属性
尽管被叫做属性,但是不能拥有任何状态,不能添加额外的字段到现有的实例中。反编译成java一样是生成了对应的静态getter/setter
val String.lastChar: Char
get() = get(length - 1)
var StringBuilder.lastChar: Char
get() = get(length - 1)
set(value) {
this.setCharAt(length -1, value)
}
println("Kotlin".lastChar)
val sb = StringBuilder("Kotlin")
sb.lastChar = 'g'
println(sb)
本文介绍了Kotlin的扩展函数和扩展属性。扩展函数和属性编译后成方法,首个参数是扩展接收者。扩展函数可在不修改源文件时为类扩展功能,有多种定义方式,如为超类、泛型、可空类型定义,且有调用和访问限制。扩展属性无状态,需自定义getter和setter。
640

被折叠的 条评论
为什么被折叠?



