版权声明:该博客为博主原创,转载请标明出处! https://blog.csdn.net/DJH2717/article/details/83306438
Kotlin 的委托属性其实从原理来讲, 很简单, 其就是将一个属性的委托给一个委托对象的约定的方法.
定义委托属性: by 关键字
var delegateProperty: Int by MyDelegate()
在 by 关键字的右边表达式, 不一定要是对应的委托对象的构造方法, 其可以是任何值, 只需要这个值能够让 kotlin 编译器用正确的参数类型调用到对应的 getVlaue 和 setValue 方法即可.
MyDelegate 的实现:
class MyDelegate {
operator fun getValue(delegateTest: DelegateTest, delegate: KProperty<*>): Int {
println("----------")
return 55
}
operator fun setValue(delegateTest: DelegateTest, delegate: KProperty<*>, newValue: Int) {
println("The property is change, oldValue is ${delegateTest}, new value is $newValue")
}
}
其对应的 getValue 和 setValue 方法只需要满足如下两条约定即可:
- 用 operator 修饰.
- 方法的形参列表必须要符合约定, 如 demo 中所示, 如果少了 Kproperty, 无法通过编译.
接下来我们来看看完整 demo 的 java 字节码, 看看委托属性的来龙去脉:
class DelegateTest {
var delegateProperty: Int by MyDelegate()
class MyDelegate {
operator fun getValue(delegateTest: DelegateTest, delegate: KProperty<*>): Int {
println("----------")
return 55
}
operator fun setValue(delegateTest: DelegateTest, delegate: KProperty<*>, newValue: Int) {
println("The property is change, oldValue is ${delegateTest}, new value is $newValue")
}
}
}
对应的 java 代码:
public final class DelegateTest {
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(DelegateTest.class), "delegateProperty", "getDelegateProperty()I"))};
@NotNull
private final DelegateTest.MyDelegate delegateProperty$delegate = new DelegateTest.MyDelegate();
public final int getDelegateProperty() {
return this.delegateProperty$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setDelegateProperty(int var1) {
this.delegateProperty$delegate.setValue(this, $$delegatedProperties[0], var1);
}
public static final class MyDelegate {
public final int getValue(@NotNull DelegateTest delegateTest, @NotNull KProperty delegate) {
Intrinsics.checkParameterIsNotNull(delegateTest, "delegateTest");
Intrinsics.checkParameterIsNotNull(delegate, "delegate");
String var3 = "----------";
System.out.println(var3);
return 55;
}
public final void setValue(@NotNull DelegateTest delegateTest, @NotNull KProperty delegate, int newValue) {
Intrinsics.checkParameterIsNotNull(delegateTest, "delegateTest");
Intrinsics.checkParameterIsNotNull(delegate, "delegate");
String var4 = "The property is change, oldValue is " + delegateTest + ", new value is " + newValue;
System.out.println(var4);
}
}
}
我们看到, 在一个类中定义一个委托属性, 这个字段并不会成为这个类的成员变量, 而是持有了对应的委托对象的引用, 同时会生成对应的get 和 set 方法, 然后通过调用委托对象对应的方法来获取值.
那么按理说我们每次访问委托属性时, 这个值都会从 get 方法中获取, 验证 demo 如下:
object Demo {
@JvmStatic
fun main(args: Array<String>) {
val delegateTest = DelegateTest()
println(delegateTest.delegateProperty)
println(delegateTest.delegateProperty)
println(delegateTest.delegateProperty)
}
}
输出:
----------
55
----------
55
----------
55
我们看到, 的确如此, 在每次访问时, 都是重新调用了 get 方法来获取其值.
除了我们自定义一个委托类来实现委托属性外, kotlin 还提供了几个标准的委托 api:
class DelegateDemo {
val myLazy by lazy { 1 } // 只能用在 val 变量
var observable by Delegates.observable(66) { _, old, new ->
println("Observable is change $old -> $new")
}
var vetoAble by Delegates.vetoable(88) { _, old, new ->
println("Veto is change $old -> $new")
return@vetoable new > 88
}
var notNull by Delegates.notNull<Int>() // 和 lateinit var 很类似, 但是其可以用在基本类型
}
主要说下, Delegates.observable 和 vetoable 的区别:
- 这两个标准的委托类, 都可以监听被委托的属性更改.
- observable 的回调是在 值 已经更改之后, 对值的更改没有干涉权利.
- 而 vetoable 就如他的名字一样, "可否决" 的, 其回调在属性更改之前, 可以否定更改.