Kotlin系列(二十三):秘技之委托属性
目录
- 更多分享:www.catbro.cn
一、前言:
- 虽然之前了解Kotlin原生支持的委托模式特性时比较尴尬,但是其提供的委托属性确实及其强大及好用的一个特性。
- 下面我们将通过分析kotlin的委托属性及其对应的java代码来更加深入地学习和理解Kotlin所提供的特性的内部原理。
二、委托属性
- 有一些常见的属性类型,虽然我们可以在每次需要的时候手动实现它们,但是如果能够为大家把他们只实现一次并放入一个库会更好。
- 例如包括:
- 1、延迟属性(lazy properties): 其值只在首次访问时计算,在Android等移动端领域使用能极好的控制启动速度,不是必要的属性可以延迟加载;
- 2、可观察属性(observable properties): 监听器会收到有关此属性变更的通知;
- 3、把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中,属性过多时管理方便。
- 为了涵盖这些(以及其他)情况,Kotlin 支持 委托属性:
委托属性代码的学习
-
以下我们便通过源代码来学习其委托属性
-
1、创建一个Boss类,其工作需要秘书进行代理完成,因为我是老板嘛……( ̄∇ ̄)
package com.anjie.demo /** * Created by 安杰 on 2017/11/2. */ class Boss { var workd: String by Secretary() }
-
可以看到,语法很简单,我们只需要记住by关键字即可
-
然后我们声明一个秘书类Secretary
package com.anjie.demo import kotlin.reflect.KProperty /** * Created by 安杰 on 2017/11/2. */ class Secretary { operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name} in $thisRef.'") } }
-
如上,其代理原理为:
- 1、被代理字段workd的setter()会委托给代理类的setValue()方法;
- 2、被代理字段workd的getter()会委托给代理类的getValue()方法;
- 所以设置了代理类之后,当被代理的字段发生变化时,我们便可在代理类里面进行接收和处理。
-
测试代码如下:
@Test fun test1() { val b = Boss() b.workd="sleep" println(b.workd) }
-
结果输出如下:
>sleep has been assigned to 'workd in com.anjie.demo.Boss@5ccd43c2.' com.anjie.demo.Boss@5ccd43c2, thank you for delegating 'workd' to me!
-
代码解析:
-
可以看到thisRef==被代理的类,property存储了被代理的属性,property.name则为属性的名称;value为给被代理字段赋值时传递的值。
-
我的天,怎么那么厉害?其实内部原理很简单,只是kotlin帮我们做了点事而已,我们看下Boss类对应的java代码:
public final class Boss { static final KProperty[] $delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Boss.class), "workd", "getWorkd()Ljava/lang/String;"))}; @NotNull private final Secretary workd$delegate = new Secretary(); @NotNull public final String getWorkd() { return this.workd$delegate.getValue(this, $delegatedProperties[0]); } public final void setWorkd(@NotNull String var1) { Intrinsics.checkParameterIsNotNull(var1, ""); this.workd$delegate.setValue(this, $delegatedProperties[0], var1); } }
-
代码解析:
-
可以看到,当粗案件Boss时,内部生成类一个代理成员-Secretary workd$delegate;
-
当我们访问被代理字段workd时,其setter和getter会被调用,而Setter和getter里面再调用了代理类对应的方法,并将值传进入,如此我们的代理对象便能接收到了。
-
OK,相信看了上面的代码的你将会觉得Kotlin的委托属性不再神秘!
-
注意:因为设置了代理后,setter和getter需要kotlin来生成,所以我们就不能够再重写被代理属性的setter和getter了。
三、总结:
- 通过分析Kotlin对应Java代码,我们很好的学习了Kotlin中代理属性的使用及其原理。
- 相信看完本章后,对于Kotlin的委托属性的使用对于你来说将是非常简单的。