前言
在上一篇文章中降到了lazy{""}
作为koltin的属性代理对象,在kotlin中,除了lazy还有一些其他的属性代理方式。
关于by关键字
还是先复习一下by关键字的使用方法
val(r) [变量名] by [代理对象]
EXP:val a by lazy{"huang"}
也就是说,by之后跟的是一个对象,这是一个存在getValue
方法的实例对象!
如果能认识大这一点,那么by关键字就很简单了。直接来看看到底有哪些属性代理对象吧。
属性代理对象们
一共有三个,分别是下面三个
Delegates.notNull<T>
Delegates.observable<T>
Delegates.vetoable<T>
先解释一下是干啥的,然后再告诉你为什么。
Delegates.notNull<T>
表示属性不为空,如果为空,则抛出异常,相当于java版本的不给初始值的属性,默认为nullDelegates.observable<T>
表示属性可观测,在设置值的前后提供监听方法,函数入参包含了初值,所以不为空,相当于给了初值并设置了监听Delegates.vetoable<T>
表示属性设置成功需要满足一定的条件,这个方法返回的对象是Delegates.observable<T>
的一个子对象,可以一起分析
整体看,这三个方法都返回一个ReadWriteProperty<in R, T>
对象
先看看这个对象的源码:
**
* Base interface that can be used for implementing property delegates of read-write properties.
*
* This is provided only for convenience; you don't have to extend this interface
* as long as your property delegate has methods with the same signatures.
*
* @param R the type of object which owns the delegated property.
* @param T the type of the property value.
*/
public interface ReadWriteProperty<in R, T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: R, property: KProperty<*>): T
/**
* Sets the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @param value the value to set.
*/
public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
你看,果然实现了getValue
方法,并且同时实现了setValue
方法,再看看注释,这个接口就是为了给可读写属性用作代理的,简直是不要太方便啊。
看看这个接口的实现类
- 1.
NotNullVar
private class NotNullVar<T : Any>() : ReadWriteProperty<Any?, T> {
private var value: T? = null
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
- 2.
ObservableProperty
/**
* Implements the core logic of a property delegate for a read/write property that calls callback functions when changed.
* @param initialValue the initial value of the property.
*/
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
/**
* The callback which is called before a change to the property value is attempted.
* The value of the property hasn't been changed yet, when this callback is invoked.
* If the callback returns `true` the value of the property is being set to the new value,
* and if the callback returns `false` the new value is discarded and the property remains its old value.
*/
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
/**
* The callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*/
protected open fun afterChange(property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}
在看看前面分析的kotlin提供的三种初始化方式,结构自然就出来了
Delegates.notNull<T>
对应NotNullVar
Delegates.observable<T>
对应ObservableProperty
Delegates.vetoable<T>
对应ObservableProperty
当然,我们也可以更直接一点,自己构造一个对象,继承ObservableProperty
来完成我们自己特殊的需求
var e by object : ObservableProperty<String>("hhhh") {
override fun beforeChange(property: KProperty<*>, oldValue: String, newValue: String): Boolean {
val flag = oldValue.length < newValue.length
println("'$newValue'长度${if (flag) "大" else "小"}于'$oldValue', 修改${if (flag) "成功" else "失败"}!")
return flag // 为false则允许修改
}
override fun afterChange(property: KProperty<*>, oldValue: String, newValue: String) {
println("'$oldValue' 被修改为 '$newValue'!")
}
}
下面提供我在学习的时候自己写的一个小demo,里面有一些例子,感兴趣的可以跑跑看,记得结合show kotlin bytecode,对照反编译的java代码食用更佳哦!
package delegate
import kotlin.properties.Delegates
import kotlin.properties.ObservableProperty
import kotlin.reflect.KProperty
class M {
val s: String by MyDelegate { "Hello" }
var a by Delegates.notNull<String>()
var b by Delegates.observable("b") { _: KProperty<*>, oldValue: String, newValue: String ->
println("'$oldValue' has been changed by '$newValue'!")
}
var c by Delegates.vetoable("world") { _: KProperty<*>, oldValue: String, newValue: String ->
oldValue.length < newValue.length
}
val d by lazy { "d" }
var e by object : ObservableProperty<String>("hhhh") {
override fun beforeChange(property: KProperty<*>, oldValue: String, newValue: String): Boolean {
val flag = oldValue.length < newValue.length
println("'$newValue'长度${if (flag) "大" else "小"}于'$oldValue', 修改${if (flag) "成功" else "失败"}!")
return flag // 为false则允许修改
}
override fun afterChange(property: KProperty<*>, oldValue: String, newValue: String) {
println("'$oldValue' 被修改为 '$newValue'!")
}
}
}
class MyDelegate<T>(val init: () -> T) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return init()
}
}
fun main() {
val m = M()
println(m.s)
// println(m.a)
println(m.b)
println(m.c)
m.e = "hh"
m.e = "hhhhhh"
}
***分割线****
注意到getValue和setValue竟然是两个operator
方法,那么它们是实现了哪个操作符呢?没错,就是等号=
,怪不得kotlin不让我重载这个操作符,原来它被用在属性代理里了。
目前kotlin还不支持直接点进去查看等号的具体实现,也就没有其他操作符那么方便的看源码了。不过想看的话,点到对应的属性,找熟悉的by关键字,然后看看by关键字后面的代理对象的实现就ok啦。
网友评论