1 類委托
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // 輸出 10
}
Derived 的超類型列表中的 by句表示b 將會在 Derived 中內部存儲。 并且編譯器將成轉發(fā)給 b 的所有 Base 的法。
2 委托屬性
class Example {
var p: String by Delegate()
}
語法是: val/var <屬性名>: <類型> by <表達式>。
屬性對應的 get()(和 set() )會被委托給表達式的getValue() 和 setValue()。
第一個參數是 p 所在對象的引用、第二個參數保存了對 p屬性自身的描述;
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.'")
}
}
對于只讀屬性(即 val 聲明的),委托必須提供名為 getValue 的函數,該函數接受以下參數:
thisRef 必須與屬性所有者類型(對于擴展屬性指被擴展的類型)相同或者是它的超類型。
property 必須是類型 KProperty<*>或其超類型。
這個函數必須返回與屬性相同的類型(或其類型)。
對于可變屬性(即 var 聲明的),委托必須額外提供 setValue 的函數,該函數接受以下參數:
thisRef 同 getValue() ;
property 同 getValue() ;
new value 必須和屬性同類型或者是它的超類型。
getValue() 或/和 setValue() 函數可以通過委托類的成員函數提供或者由擴展函數提供。 兩函數都需要 operator 關鍵字來標記。
委托類可以實現包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty。
這倆接口是在 Kotlin 標準庫中聲明的:
interface ReadOnlyProperty<in R, out T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
3 延遲屬性 Lazy
val lazyValue: String by lazy {
"Hello"
}
延遲加載屬性(lazy property): 屬性值只在初次訪問時才會計算;
get()會執(zhí)行l(wèi)ambda表達式并記錄結果,后續(xù)的get方法將只返回結果。
var類型屬性不能設置為延遲加載屬性,因為在lazy中并沒有setValue(…)方法。
lazy操作符是線程安全的。如果在不考慮多線程問題或者想提高更多的性能,也可以使
用 lazy(LazyThreadSafeMode.NONE){ … } 。
在LazyThreadSafetyMode中聲明了幾種,[Lazy]實例在多個線程之間同步訪問的形式:
SYNCHRONIZED:鎖定,用于確保只有一個線程可以初始化[Lazy]實例。
PUBLICATION:初始化函數可以在并發(fā)訪問未初始化的[Lazy]實例值時調用幾次,,但只有第一個返回的值將被用作[Lazy]實例的值。
NONE:沒有鎖用于同步對[Lazy]實例值的訪問; 如果從多個線程訪問實例,是線程不安全的。此模式應僅在高性能至關重要,并且[Lazy]實例被保證永遠不會從多個線程初始化時使用。
class App : Application() {
val database: SQLiteOpenHelper by lazy {
MyDatabaseHelper(applicationContext)
}
override fun onCreate() {
super.onCreate()
val db = database.writableDatabase
}
}
4 可觀察屬性(Observable)
Delegates.observable() 函數接受兩個參數:
第一個是初始化值,
第二個是屬性值變化事件的響應器(handler).
這種形式的委托,采用了觀察者模式,其會檢測可觀察屬性的變化,當被觀察屬性的setter()方法被調用的時候,響應器(handler)都會被調用(在屬性賦值處理完成之后)并自動執(zhí)行執(zhí)行的lambda表達式,同時響應器會收到三個參數:被賦值的屬性, 賦值前的舊屬性值, 以及賦值后的新屬性值。
class ViewModel(val db: MyDatabase) {
var myProperty by Delegates.observable("") {
d, old, new ->
db.saveChanges(this, new)
}
}
5 Map中映射值
在像解析 JSON 或者做其他“動態(tài)”事情中。把map映射到屬性
import kotlin.properties.getValue
class Configuration(map: Map<String, Any?>) {
val width: Int by map
val height: Int by map
val dp: Int by map
val deviceName: String by map
}
conf = Configuration(mapOf(
"width" to 1080,
"height" to 720,
"dp" to 240,
"deviceName" to "mydevice"
))
6 局部委托屬性
你可以將局部變量聲明為委托屬性。
memoizedFoo 只有someCondition滿足條件,第一調用才會初始化
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
if (someCondition && memoizedFoo.isValid()) {
memoizedFoo.doSomething()
}
}