深入Kotlin - 专项 - 委托属性-1
2017-09-01 20:56
183 查看
委托属性
最常见的一类属性就是简单地从幕后字段中读取(以及可能的写入)。默认的另一种,使用自定义getter和setter可以实现属性的任何行为。
而介于两者之间的,属性又有哪些常见的模式呢?
惰性值、通过键值从映射读取、访问数据库、访问通知侦听器等等。
下面我们将依次来看这些特殊的模式:首先我们来了解一下和委托相关的内容
类委托
委托模式已经被证明是实现继承的一个很好的代替方式,而Kotlin可以零样板代码地原生支持它。具体地用代码说话(哈哈)interface Base{ fun print() } class BaseImpl(val x:Int):Base{ override fun print() { println(x) } } class Derived(b:Base):Base by b fun main(args: Array<String>) { val b = BaseImpl(10) Derived(b).print() }
运行结果:输出10
这里我们看看Derived的实现和我们通常看到地不同:
它继承了接口Base但没有重写print()方法
使用了by关键字
最后的结果输出10,说明Derived最后调用的是b的print()方法
从上面可以看出:类Derived继承接口Base,并将其所有共有的方法通过by关键字委托给一个指定的对象b
注意这里b作为一个参数传入到了Dervied内部,具体细节我们可以通过查看字节码来看看:
public final class Derived implements Base { // $FF: synthetic field private final Base $$delegate_0; public Derived(@NotNull Base b) { Intrinsics.checkParameterIsNotNull(b, "b"); super(); this.$$delegate_0 = b; } public void print() { this.$$delegate_0.print(); } }
反编译之后我们可以清楚的看到:Kotlin自动为我们在Derived类内部声明了一个私有变量来保存b,从变量名我们就可以看出这保存的是委托(delegate)变量。不仅如此,Kotlin还自动为我们重写了print()方法,并且最终调用的是b的print()方法
结论:Derived 的超类型列表中的by-子句表示b将会在Derived中内部存储。并且编译器将生成转发给b的所有Base的方法。
用途:我们可以通过控制b来控制Derived实现不同的行为,例如:给老板配车,我们传入不同的车型,就可以开不同的车,且老板不用做任何修改,而且非常简洁。相反,在java中我们重复的多写好多代码
注:如果我们在Derived中override重写了print()方法,那么调用print()方法的时候最终将会调用Derived的print()方法,Kotlin编译器将不会再为我们生成print()方法。这就如同,老板配车但是司机固定一样。。。
关于类的委托到此就结束了,下面我们来看看属性的委托:
委托属性
有一些常见的属性类型,如:延迟属性(lazy properties):其值只在首次访问时计算
可观察属性(observable properties):监听器会收到有关次属性变更的通知
把多个属性存储在一个映射(map)中,而不是每个存在单独的字段中
虽然我们可以每次在需要使用它们的时候动手去实现它们,那么这意味着同样的代码我们要去实现n次。。。(心累)
如果能有一个库能帮我们解决这些问题该多好呀,实际是不可能的,因为需求不同,情况太多了,一个库无法包含所有的情况。
为了涵盖这些(以及其他)情况,Kotlin支持委托属性。
语法:val/var \<属性名>: \<类型> by \<表达式>
by后面的表达式就是 委托,属性对应的 get() 和 set() 方法会被委托给它的getValue() 和 setValue()方法。
属性的委托不必实现任何接口,只需要提供一个getValue() 方法和 setValue()方法。
唉╮(╯▽╰)╭,这么说还是太抽象了,我们还是来看代码说话吧:
class Example{ var p:String by Delegate() } class Delegate { operator fun getValue(example: Example, property: KProperty<*>): String { return "$example, thank you for delegating '${property.name}' to me!" } operator fun setValue(example: Example, property: KProperty<*>, s: String) { println("$s has been assigned to '${property.name}' in $example.'") } } fun main(args: Array<String>) { val e = Example() e.p = "lxx" println(e.p) }
同样我们来看看字节码反编译的结果:
public final class Example { @NotNull private final Delegate p$delegate = new Delegate(); // $FF: synthetic field static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Example.class), "p", "getP()Ljava/lang/String;"))}; @NotNull public final String getP() { return this.p$delegate.getValue(this, $$delegatedProperties[0]); } public final void setP(@NotNull String var1) { Intrinsics.checkParameterIsNotNull(var1, "<set-?>"); this.p$delegate.setValue(this, $$delegatedProperties[0], var1); } }
还记得上面的类委托吗,是不是很相似,确实感觉差不多,Example内部也多了一个私有变量,不同的就是类委托中我们是直接委托给了一个对象(通过参数传入),而这里我们是new了一个对象,但这其实并没有影响,我们在类委托中同样可以这么做
有了这个方法,我们是不是很容易就可以实现对属性的控制了呢,而且是不是非常简洁,通过关键字by我们可以少写很多代码,而且非常明了。
不仅如此,Kotlin为了更好的帮助我们,Kotlin标准库中还提供了几种非常使用的委托工厂方法来方便我们使用。
1. 延迟属性Lazy
lazy()是接受一个lambda并返回一个Lazy\class LazyValueDemo { val lazyValue: String by lazy { println("computed!") "Hello" } } fun main(args: Array<String>) { val ts = LazyValueDemo() println(ts.lazyValue) println(ts.lazyValue) }
输出:
computed!
Hello
Hello
关于这段,暂时只是根据代码简单了解,还没有弄得很清楚::>_\<::
附录:
默认情况下,对于 lazy
属性的求值是同步锁的(synchronized):该值只在一个线程中计算,并且所有线程会看到相同的值。如果初始化委托的同步锁不是
必需的,这样多个线程可以同时执行,那么将 LazyThreadSafetyMode.PUBLICATION 作为参数传递给 lazy()
函数。而如果你确定初始化将总是 发生在单个线程,那么你可以使用 LazyThreadSafetyMode.NONE
模式,它不会有任何线程安全的保证和相关的开销。
2. 可观察属性 Observable
待补充,有些东西暂时没弄懂~~(>_\<)~~3. 把属性存储在映射中 map
相关文章推荐
- 深入Kotlin - 专项 - 幕后字段、幕后属性
- Kotlin的委托属性和区间
- Kotlin的属性委托:无上下文情况下Android的赋值(KAD 15)
- Kotlin的属性委托:无上下文情况下Android的赋值(KAD 15)
- 深入Kotlin - 专项 - 扩展函数
- kotlin委托属性+SharedPreference实例
- Kotlin的属性委托:无上下文情况下Android的赋值(KAD 15)
- Kotlin学习(十八): 委托模式(Delegate)和委托属性(Delegate Properties)
- Kotlin随笔 委托属性之延迟加载
- Kotlin的属性委托:无上下文情况下Android的赋值(KAD 15)
- Kotlin-委托属性
- Kotlin笔记(七)——委托属性(Delegated Properties)
- Kotlin的属性委托:无上下文情况下Android的赋值(KAD 15)
- Kotlin的属性委托:无上下文情况下Android的赋值(KAD 15)
- 深入Kotlin - 专项 - Lambda表达式
- Kotlin开发Android笔记11:Kotlin中属性委托
- Kotlin-20.代理/委托属性(delegated properties)
- Kotlin开发笔记之委托属性与区间(译)
- 学习kotlin第十天_对象、委托、委托属性
- C++Builder 2010深入TApplication类之属性