Kotlin Reference (十四) 委托类和委托属性
来源:互联网 发布:网络名字伤感两个字 编辑:程序博客网 时间:2024/05/17 17:42
KotLin 相关文档
官方在线Reference
kotlin-docs.pdf
Kotlin for android Developers 中文翻译
Kotlin开发工具集成,相关平台支持指南
Kotlin开源项目与Libraries
Kotlin开源项目、资源、书籍及课程搜索平台
Google’s sample projects written in Kotlin
Kotlin and Android
Kotlin委托机制
委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。
Kotlin 直接支持委托模式,更加优雅,简洁。Kotlin 通过关键字 by 实现委托。
委托类 (Class Delegation)
例,
interface Base { fun print()}class BaseImpl(val x: Int) : Base { override fun print() { print(x) }}class Derived(b: Base) : Base by b { fun add() { }}fun main(args: Array<String>) { val b = BaseImpl(10) Derived(b).print() // prints 10 Derived(b).add()}
在基类列表上使用by
子句,表示,Derived类的内部对象b,会生成Base的所有公共函数。这时调用Derived的属于Base的公共函数,就会委托调用b对象的对应函数。
Derived是一个委托类,其对应的委托实例就是构造函数中Base的实例b
委托属性 (Delegated Properties)
有一些常见的属性,虽然我们可以每次需要时手动实现它们,但现在只需要如下形式的使用,即可实现。这些属性,如:
lazy properties
只在第一次访问时进行值计算observable properties
监听获取关于属性变化的通知storing properties
将属性存储在一个Map中
委托属性语法
例,
class Delegate { 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.'") }}class Example { var p: String by Delegate()}fun main(args: Array<String>) { val example = Example() example.p = "stone" println(example.p)}
输出:
stone has been assigned to 'p in com.stone.clazzobj.delegation.Example@238e0d81.'com.stone.clazzobj.delegation.Example@238e0d81, thank you for delegating 'p' to me!
委托属性语法: val/var <property name>: <Type> by <expression>
如,上例中的Example的属性p
这里将属性p的get/set委托给Delegate类的getValue/setValue函数来处理。
属性委托类,如Delegate类,其可以在形式上继承/实现一个基类/接口(这里指非特定的),然而该接口的函数在外部并不能由委托属性调用,所以继承/实现的特性,在这里并没有什么大的意义
标准委托属性
Kotlin标准库,为如下几种有用的委托形式,提供了相应的工厂方法
- lazy
val lazyValue: String by lazy { println("computed!") //多次调用 只会输出一次 "Hello"}
查看lazy源码,发现它调用的是:
public fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
SynchronizedLazyImpl这是一个同步执行的函数,内部实现是加了synchronized的同步代码块的;所以在多线程环境中,第一个进入同步代码块执行出的结果,就是lazy-property的值。
再看lazy的一个重载方法:
public fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> = when (mode) { LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer) LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer) LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer) }
使用,如
val lazyValue: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {...}
LazyThreadSafetyMode对应的三种模式:
a. SYNCHRONIZED 同步
b. PUBLICATION 发布。内部的计算过程可能被多次访问,但内部的属性是一个Volatile修饰的属性,所以在多线程环境中,被第一次访问获取数据后,此后的其它线程都共享该值。
c. NONE
未对多线程环境,做任何处理。
所以在多线程环境中使用,会造成:计算和返回值都可能处在多个线程中。
注:lazy属性,只能声明为 val的,即它是只能get的
- Observable
需要在属性后跟by Delegates.observable()
,即调用这个方法设定属性值。该方法是两个参数:初始值,lambda表达式(即处理值的语句块)。
例,
import kotlin.properties.Delegatesclass User { var name: String by Delegates.observable("<no name>") { property, oldValue, newValue -> println("$oldValue -> $newValue") } }fun main(args: Array<String>) { val user = User() user.name = "first" user.name = "second"}
输出:
<no name> -> firstfirst -> second
Delegates.observable()中,使用的lambda表达式,其参数:
I. property:在这指属性name
II. oldValue: 旧值,首次即为指定的初始值
III. newValue:新set的值
最终属性值=new值
还有个Delegates.vetoable(),跟Delegates.observable()类似,只是lambda表达式的返回值为Boolean。
返回true:属性值=new值
返回false:属性值=old值observable 属性,可以定为val的,不过既然要监听属性的变化,还是用var较好
- Storing Properties in a Map
将属性委托给(存进)一个Map。
例,
class Per(val map: Map<String, Any?>) { val name: String by map val age: Int by map}fun main(args: Array<String>) { val per = Per(mapOf("name" to "John Doe", "age" to 25)) println(per.name) println(per.age)}
输出:
John Doe25
也可以使用一个
var map
,即map的类型为MutableMap
局部委托属性
在kotlin1.1后,可以定义局部的委托属性。如,
class Foo { fun isValid(): Boolean { return Random().nextBoolean() } fun doSomething() { println("doSomething") }}fun example(computeFoo: () -> Foo) { val memoizedFoo by lazy(computeFoo) //memoizedFoo: Foo if (memoizedFoo.isValid()) { memoizedFoo.doSomething() }// var p: String by Delegate() //可以有其它形式的委托属性}fun main(args: Array<String>) { example { println("生成Foo") Foo() }}
上例的example(),接受一个函数参数,该函数返回Foo类型对象。
memoizedFoo,就是一个局部委托属性;这里委托的是public fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
这个函数,该lazy函数接受一个函数参数。
局部委托属性也可以是其它的委托属性形式。
委托属性给一个类实例之总结
对于一个val修饰的只读属性
它的委托必须提供一个名为
getValue
的函数。该函数中的两个参数的意义,如下
thisRef : 其类型,必须是委托属性的所有者或其super类型
property : 必须是KProperty<*>
或其super类型KCallable<*>
对于一个var修饰的可变属性
其含有参数,除了上述两个外,还多一个new-value值
注意getValue/setValue函数的声明以operator开始
这两个函数,可以直接定义成委托类的成员函数,或委托类的扩展函数。后者对于在原始类中未提供它们时,提供了方便
ReadOnlyProperty 和 ReadWriteProperty
属性的委托类,可以实现两个接口,kotlin.properties.ReadOnlyProperty
和kotlin.properties.ReadWriteProperty
;这两个接口中,声明了getValue(var和val属性)/setValue(var属性)函数。例,
class Example1: Super() { val p1: String by Delegate1()}class Delegate1: ReadOnlyProperty<Example1, String> { override fun getValue(thisRef: Example1, property: KProperty<*>): String { return "" }}
不实现这两个接口也是可以的,如之前使用 operator声明的getValue/setValue函数
委托属性转化规则
声明的委托属性,会由编译器产生一个隐藏属性,且会生成对应的get/set方法。
如,
class C { var prop: Type by MyDelegate()}
在编译器中,会产生如下代码:
class C { private val prop$delegate = MyDelegate() var prop: Type get() = prop$delegate.getValue(this, this::prop) set(value: Type) = prop$delegate.setValue(this, this::prop, value)}
provideDelegate函数提供委托实例
在kotlin1.1,提供了provideDelegate函数,它可以为属性提供对象委托逻辑。
如果 by 右侧所使用的对象将 provideDelegate(函数名不能随意变更) 定义为成员或扩展函数,那么会调用该函数来 创建属性委托实例;且要求委托实例的类,要实现 ReadOnlyProperty 或 ReadWriteProperty接口
例,
class Dele(val id: String): ReadOnlyProperty<MyUI, String> { override fun getValue(thisRef: MyUI, property: KProperty<*>): String { return "${UUID.randomUUID()}_$id" }}class ResourceID { private constructor(id: String) { this.id = id } open val id: String companion object { val image_id = ResourceID("1") val text_id: ResourceID = ResourceID("2") }}class ResourceLoader(resId: ResourceID) { private val resourceID = resId operator fun provideDelegate(thisRef: MyUI, prop: KProperty<*>): ReadOnlyProperty<MyUI, String> { checkProperty(thisRef, prop.name) // create delegate return Dele(resourceID.id+"") } private fun checkProperty(thisRef: MyUI, name: String) { if (name.equals("image")) { //... } }}fun MyUI.bindResource(id: ResourceID): ResourceLoader { return ResourceLoader(id)}class MyUI { val image by bindResource(ResourceID.image_id) //bindResource()产生委托对象 val text by bindResource(ResourceID.text_id)}fun main(args: Array<String>) { println("image-id = " + MyUI().image) println("txt-id = " + MyUI().text)}
上例中,找到by关键字,其右侧调用了bindResource创建委托类实例。
bindResource(这是一个扩展函数)返回ResourceLoader类型的实例。
ResourceLoader中定义了一个operator声明的函数,名为provideDelegate,其返回真正的委托类Dele的实例对象。
Dele中,getValue函数,返回一个”拼接了UUID前缀+资源类型id”的字符串。
使用provideDelegate函数的委托属性转化规则
class C { var prop: Type by MyDelegate()}// this code is generated by the compiler// when the 'provideDelegate' function is available: class C { // calling "provideDelegate" to create the additional "delegate" property private val prop$delegate = MyDelegate().provideDelegate(this, this::prop) val prop: Type}
- Kotlin Reference (十四) 委托类和委托属性
- Kotlin-委托属性
- Kotlin的委托属性和区间
- kotlin委托属性+SharedPreference实例
- Kotlin学习(十八): 委托模式(Delegate)和委托属性(Delegate Properties)
- Kotlin-委托
- Kotlin -- 委托
- kotlin 委托
- Kotlin委托
- Kotlin类和对象 (十三)--- 委托属性(Delegated Properties)
- 学习kotlin第十天_对象、委托、委托属性
- Kotlin随笔 委托属性之延迟加载
- Kotlin-20.代理/委托属性(delegated properties)
- kotlin学习笔记——委托属性
- Kotlin开发Android笔记11:Kotlin中属性委托
- Kotlin类和对象 (十二)--- 委托(Delegation)
- Kotlin Reference (十四) Generics
- Kotlin-19.代理/委托类(Delegation)
- Maven生成可以直接运行的jar包的多种方式
- 坑图
- MyEclipse安装JS代码提示(Spket插件)
- 大数据-零基础学习hadoop到上手工作线路指导(初级篇)
- Gson转换
- Kotlin Reference (十四) 委托类和委托属性
- 图像处理之常见二值化方法汇总
- Android中的MVP
- ios runtime 获取 class 属性
- 20170713智慧运营平台工作
- xam之路二
- Android可更换布局的换肤方案
- java中泛型创建数组的总结
- mysql用户管理