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