官方文檔: http://kotlinlang.org/docs/reference/delegated-properties.html
1.委托屬性
一些常見的屬性類型:
懶加載屬性(lazy properties): 只在首次訪問時(shí)計(jì)算屬性值;
可觀察屬性(observable properties): 監(jiān)聽器可以收到此屬性變化的通知;
一個(gè)映射(map)存儲多個(gè)屬性,而不是一個(gè)屬性對應(yīng)一個(gè)字段!
為涵蓋這些情況,Kotlin支持委托屬性(delegated properties):
import kotlin.reflect.KProperty //導(dǎo)入庫
class Example {
//by Delegate()表示: 屬性p的get()和set()會(huì)被委托給Delegate的getValue()和setValue()
var p: String by Delegate()
}
class Delegate() {
// 取代Example的屬性p的get()
operator fun getValue(t: Any?, prop: KProperty<*>): String {
// 第一個(gè)參數(shù)t: 被代理的對象(本例中Example對象)
// 第二參數(shù)prop: 被代理的對象的屬性(本例中Example對象的屬性p)
return "$t, ${prop.name}"
}
// 取代Example的屬性p的set()
operator fun setValue(t: Any?, prop: KProperty<*>, value: String) {
// 第三個(gè)參數(shù): 被代理的對象的屬性值(本例中Example對象的屬性p的值)
println("$t, ${prop.name}, $value")
}
}
fun main(args: Array<String>) {
val e = Example()
println(e.p) //調(diào)用get方法 輸出 Example@6267c3bb, p
e.p = "MyVal" //調(diào)用set方法 輸出 Example@6267c3bb, p, MyVal
}
2.懶加載屬性(lazy properties)
by lazy({ })是接受lambda并返回一個(gè)Lazy<T>對象的函數(shù),
返回對象可作為委托,實(shí)現(xiàn)了懶加載屬性(lazy properties):
val a: String by lazy {
//第一次調(diào)用會(huì)執(zhí)行該lamda表達(dá)式,并記錄結(jié)果
//后續(xù)調(diào)用只返回已記錄的結(jié)果
println("******")
"Hello"
"返回結(jié)果" //lamda表達(dá)式最后一行作為lazy函數(shù)返回值,記錄結(jié)果
}
fun main(args: Array<String>) {
println(a)
println(a)
}
輸出:
******
"返回結(jié)果"
"返回結(jié)果"
默認(rèn)情況下,lazy{}是同步鎖住(synchronized): 只能有一個(gè)線程執(zhí)行,其它線程必須等待!
如果需要多個(gè)線程同時(shí)執(zhí)行l(wèi)azy{},那么傳遞參數(shù)LazyThreadSafetyMode.PUBLICATION給lazy()函數(shù)
如果確定lazy{}總是單個(gè)線程,那么傳遞參數(shù)LazyThreadSafetyMode.NONE,不保證線程安全!
val a: String by lazy(LazyThreadSafetyMode.NONE){
...
}
val a: String by lazy(LazyThreadSafetyMode.PUBLICATION){
...
}
自kotlin 1.1起,可將局部變量聲明為委托屬性,例如lazy懶加載屬性:
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
if (someCondition && memoizedFoo.isValid()) {
memoizedFoo.doSomething()
}
}
3.可觀察屬性(observable properties)
Delegates.observable()有兩個(gè)參數(shù): 初始值、屬性變化時(shí)的回調(diào)(handler)
import kotlin.properties.Delegates //導(dǎo)入庫
class User {
//如果要攔截(veto否決)賦值,就用vetoable()取代observable()!
var name: String by Delegates.observable("initName") {
//回調(diào)有三個(gè)參數(shù):被觀察的屬性固逗、屬性舊值和屬性新值
prop, old, new -> println("$old ---> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "name111"
user.name = "name222"
}
輸出:
initName ---> name111
name111 ---> name222
4.一個(gè)映射(map)存儲多個(gè)屬性(Storing Properties in a Map)
一個(gè)映射(map)存儲多個(gè)屬性,這時(shí)可用映射實(shí)例對象作為委托,實(shí)現(xiàn)委托屬性!
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
//1.使用map代理多個(gè)屬性
val user = User(mapOf(
"name" to "lioil",
"age" to 24
))
//2.從map中讀取多個(gè)屬性值
println(user.name) // 輸出 lioil
println(user.age) // 輸出 24
//把只讀Map改為可變MutableMap,也適用于var屬性
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
簡書:http://www.reibang.com/p/2464a5106f12
CSDN博客: http://blog.csdn.net/qq_32115439/article/details/73751666
GitHub博客:http://lioil.win/2017/06/26/Kotlin-delegated-properties.html
Coding博客:http://c.lioil.win/2017/06/26/Kotlin-delegated-properties.html