簡述
在java中一些屬性的具有相同的行為怎么辦屉来,抽象出類然后再去依賴調(diào)用右遭,而在Kotlin中只需要一個by關(guān)鍵字就能省去繁瑣的依賴勾笆。屬性的委托主要是統(tǒng)一實現(xiàn)了對屬性的set芳肌,get困食。Kotlin 標(biāo)準(zhǔn)庫還為幾種有用的委托提供了工廠方法:
延遲屬性(lazy properties): 其值只在首次訪問時計算,
可觀察屬性(observable properties): 監(jiān)聽器會收到有關(guān)此屬性變更的通知邢疙,
把多個屬性儲存在一個映射(map)中棍弄,而不是每個存在單獨(dú)的字段中。
下面將通過編譯器的代碼例子詳細(xì)學(xué)習(xí)疟游。
例1:聲明方式
val/var <屬性名>: <類型> by <表達(dá)式>
例2:by <表達(dá)式> 這個表達(dá)式怎么寫,下面一個例子
class ByDemo{
? ? ? ? ?operator fun getValue(thisRef: Any?,property: KProperty<*>) : <類型>{
? ? ? ? ? ? ? ? ? return <類型>
? ? ? ? ?}
? ? ? ? ?operator fun setValue(thisRef: Any?,property: KProperty<*>,value:<類型>){
? ? ? ? ? ? ? ? ? ?print()
? ? ? ? ?}
}
解釋下這個例子:
定義一個ByDemo類痕支,然后再定義兩個方法getValue(),setValue() , 方法需要operator關(guān)鍵字修飾颁虐,thisRef: Any? :thisRef是當(dāng)前屬性的對象,property: KProperty<*>:property是當(dāng)前屬性卧须,property.name 屬性名稱另绩,value:<類型> 這個就是當(dāng)前屬性的值和類型。
在定義委托表達(dá)式需要注意的點:
對于只讀屬性(也就是說val屬性), 它的委托必須提供一個名為getValue()的函數(shù)花嘶。
thisRef: Any? 必須是該屬性當(dāng)前類或者基類(Any是任何類的基類)笋籽。
property: KProperty<*>這個參數(shù)的類型必須是 KProperty<*> , 或者是它的基類。
getValue()返回值類型必須與屬性類型相同(或者是它的子類型)椭员。
value:<類型>這個參數(shù)的類型必須與屬性類型相同, 或者是它的基類
方法名不能改必須是getValue车海、setValue,并且必須用operator關(guān)鍵字修飾
接下來看下Kotlin 標(biāo)準(zhǔn)庫提供的委托
例1:lazy()是接受一個 lambda 并返回一個Lazy 實例的函數(shù)隘击,返回的實例可以作為實現(xiàn)延遲屬性的委托: 第一次調(diào)用get()會執(zhí)行已傳遞給lazy()的 lamda 表達(dá)式并記錄結(jié)果侍芝, 后續(xù)調(diào)用get()只是返回記錄的結(jié)果。
var類型屬性不能設(shè)置為延遲加載屬性埋同,因為在lazy中并沒有setValue(…)方法
lazy是線程安全的州叠。如果在不考慮多線程問題或者想提高更多的性能,也可以使
用 lazy(LazyThreadSafeMode.NONE){ … }
例2:Observable 使用是通過類Delegates.observable()調(diào)用的凶赁,需要兩個參數(shù):第一個是初始化值, 第二個是屬性值變化事件的響應(yīng)器(handler)
var name: String by Delegates.observable("demo",{
? ? ? kProperty , oldName , newName->
? ? ? ?println("kProperty:${kProperty.name}| oldName:$oldName| newName:$newName")
})
"demo" 為第一個參數(shù)咧栗,用意是給name賦值逆甜。
"demo"后面大括號內(nèi)容為第二個參數(shù),表達(dá)式有三個值:每次給name賦值都會回調(diào)它致板,就跟觀察者一樣忆绰,kProperty是當(dāng)前屬性,oldName是它的舊值可岂,newName是它的新值错敢。這里都是變量名可以隨意起名字,你也可以這樣 { a, b, c -> println( a+b+c) } 當(dāng)然這樣命名不規(guī)范不推薦缕粹,這就是為了說明可以改稚茅。
例3:Vetoable 使用也是通過 類Delegates.vetoable()調(diào)用,同樣也是兩個參數(shù)平斩,第一個是初始化值, 第二個是屬性值變化事件的響應(yīng)器(handler)亚享,是可觀察屬性(Observable)的一個特例,不同的是給屬性賦值的時候會加以判斷绘面,是否要將新值賦于該變量欺税。
var name: String by Delegates.vetoable("demo",{
? ? ? ? kProperty , oldName , newName->
? ? ? ? println("kProperty:${kProperty.name}| oldName:$oldName| newName:$newName")
? ? ? ? newName.contains("demo") //判斷新的值是否包含demo字符,有才會賦值
})
例4:notNull 使用 通過類 Delegates.notNull() 調(diào)用揭璃,在java中我們會遇到很多的null判斷晚凿,空的話會拋出異常,Kotlin為了簡化該操作瘦馍,追求高效率的工作歼秽,幫我們實現(xiàn)了該方法,下面看下源碼就明白了情组,在value等于null的時候拋出IllegalStateException異常燥筷,說該值必須初始化。
例5:map映射院崇,Kotlin給咱們提供了 map到 對象屬性的映射肆氓,主要用于json解析中,這種委托的寫法和上面的不太一樣底瓣,首先看下代碼
class User(val map: Map) {
? ? ? ?val name: String by map
? ? ? ?val age: Int by map
}
User類接受一個Map集合谢揪,會自動將 Map中key 為name的值賦給name, age為key的值賦給age濒持。這樣用起來確實挺簡單方便键耕。
總結(jié)
委托屬性在實際開發(fā)中還是會應(yīng)用很多的,這屬于kotlin中的重點之一吧柑营,需要好好研究下屈雄,到此為止,Kotlin中的類與對象就告一段落官套,不知道你們學(xué)的怎么樣酒奶,下期繼續(xù)學(xué)習(xí)kotlin中的又一個特點:空安全蚁孔。