我们知道,在Java里面,没有扩展方法这个概念,只有utils工具类,我们需要实现Java本身没有提供的功能API的时候,我们就只有自己写工具类来实现。
但kotlin里面。我们是可以基于系统提供的API对系统功能进行扩展。当然这样的扩展只对本工程有效。
扩展方法的实现形式:正常书写的方法名前加上“receiver”,也就是“要判断的对象的类名.”。
比如下面的示例,我们要判断某个String字符串的是否为空:String.isEmpty(msg:String)。其中,“String.”就是我们“要判断的对象的类名.”,“isEmpty”就是方法名:
fun String.isEmptyOrNull(): Boolean {
return this.isNullOrEmpty() || this.trim().isEmpty()
}
使用的时候很简单,我们直接这样调用即可:
println("${"sdfghj".isEmptyOrNull()}")
运行结果如下:
再来看看一个字符串填充的扩展类:
fun String.margin(start: Int = 1, end: Int = 5, char: Char = '*', separator: CharSequence = ","): String {
//这里的(start .. end)形成一个从start到end的前后闭合的一个闭区间;
//(start .. end).joinToString(separator):表示在这个闭合区间内,循环产生对象,每隔对象之间被separator隔开;
//而这个对象则由后面的“{}”大括弧里面的内容指定,具体见下面大括弧里面的注释说明:
val padding = (start..end).joinToString(separator) {
// //这里的it就表示在(start .. end)闭区间内循环产生的每个对象,比如闭区间为(1 .. 5),那么循环产生的每隔对象分别为1、2、3、4、5
// it.toString()
// //在(start .. end)闭区间内循环产生的每个对象由外界指定,比如这里指定为char,默认为“*”
char.toString()
// //在(start .. end)闭区间内循环产生的每个对象为调用该方法的字符串本身,比如外界调用该方法的字符串为"abc",那么产生的字符串即为“abc”
// this
}
return "${padding}${this}${padding}"
}
注意事项以及含义解说,注释里面写得很清楚,这里就不再多说。
假设字符串"abc"以如下方式调用:“966487”.margin(5, 10, separator = “”),那么上面的padding变量对应的字符串分别为:
1、it.toString()---->>>56789109664875678910
2、char.toString()---->>>******966487******
3、this---->>>966487966487966487966487966487966487966487966487966487966487966487966487966487
使用的时候调用方式如下:
println("966487".margin(5, 10, separator = ""))
因此扩展方法还是比较简单。我们现在再来说对自定义的某个类扩展属性property,直接上代码:
自定义的类:
class PoorGuy : Guy{
var mWealth:Double = 0.0
}
按惯例,我们先扩展一个方法:
对于PoorGuy这个类,我们可以为他定义扩展方法,在实现上,跟我们前面的扩展String.kt的方法没有区别;
fun PoorGuy.noMoney() {
println("I'm very very poor, I haven't any money to life")
}
我们还可以对PoorGuy这个类扩展属性property:
1、由于在kotlin里面,属性property <==>java里面的backing field + get + set,但是自定义的扩展属性是没有feilding存在的,因此我们不能用feilding来接收set方法里面的参数;
2、但是我们有曲折的实现方式:我们可以在PoorGuy里面创建一个public变量,用它来接受和返回变量值;
3、但是要注意我们创建的这个变量必须是public的,否则无法获取到。
var PoorGuy.wealth: Double
get() {
return mWealth
}
set(value) {
mWealth = value
}
除了扩展属性里面没有field之外,interface接口也是没有的:
1、我们知道kotlin里面,接口内部也是可以定义自有的属性property和具体方法实现的。
2、当我们定义属性property时,需要注意:接口 也是没有field的,因此他的get/set方法并没有太多的实际意义。
3、因为get得到的是一个具体的固定值,没法修改;有因为接口不存在field状态,导致不能通过field来存储set方法的值value。
4、另外,定义的get/set方法并不能被复写。
interface Guy{
var guyWealth:Double
get() {
return 0.0
}
set(value) {
当我们像下面这样写set方法的时候,IDE就会报错,提示:Property in an interface cannot have a backing field
// field = value
}
}