柚子快報(bào)激活碼778899分享:Kotlin 委托
柚子快報(bào)激活碼778899分享:Kotlin 委托
文章目錄
定義繼承/實(shí)現(xiàn)的委托屬性的委托委托給對(duì)象委托給另一個(gè)變量
自定義可委托類
定義
有時(shí)候我們需要辦成某件事但又不想自己做時(shí),可以將其交給別人做,這其實(shí)就是一種委托。Kotlin 中可以使用by關(guān)鍵字聲明委托。
繼承/實(shí)現(xiàn)的委托
某個(gè)類ClassA想要實(shí)現(xiàn)一個(gè)接口MyInterface,但是發(fā)現(xiàn)接口中的抽象方法非常多,全部實(shí)現(xiàn)非常困難。巧的是我們已經(jīng)有另一個(gè)類ClassB(或者該接口的一個(gè)對(duì)象)實(shí)現(xiàn)了該接口,此時(shí)我們可以將ClassA的實(shí)現(xiàn)MyInterface的工作委托給ClassB
interface MyInterface {
// 超多抽象方法
fun example()
}
class ClassB: MyInterface {
// 超多抽象方法的實(shí)現(xiàn)
override fun example() = print("ClassB 實(shí)現(xiàn)")
}
class ClassA(classB: ClassB): MyInterface by classB {
// ClassA 不需要自己實(shí)現(xiàn) MyInterface 的方法
}
fun main() {
val classB = ClassB()
ClassA(classB).example()
}
ClassB 實(shí)現(xiàn)
如果我們發(fā)現(xiàn)ClassB中的某個(gè)方法的實(shí)現(xiàn)并不是ClassA想要的,還可以在ClassA中聲明對(duì)MyInterface方法的重寫,此時(shí)如果調(diào)用ClassA的example則會(huì)調(diào)用新重寫的這個(gè):
interface MyInterface {
// 超多抽象方法
fun example()
}
class ClassB: MyInterface {
// 超多抽象方法的實(shí)現(xiàn)
override fun example() = print("ClassB 實(shí)現(xiàn)")
}
class ClassA(classB: ClassB): MyInterface by classB {
override fun example() = print("ClassA 實(shí)現(xiàn)")
}
fun main() {
val classB = ClassB()
ClassA(classB).example()
}
ClassA 實(shí)現(xiàn)
屬性的委托
委托給對(duì)象
我們可以將屬性 getter 和 setter 委托給某一個(gè)對(duì)象,此時(shí)會(huì)將get和set函數(shù)委托給類的getValue和setValue聲明。
val修飾的不可變變量只有 getter,因此只會(huì)將get委托給getValue。
最常見的是Lazy,我們可以使用函數(shù)lazy(后邊的 lambda 需要返回一個(gè)值作為變量的初始值,該值的類型會(huì)作為變量類型)生成一個(gè)Lazy對(duì)象,并將某一個(gè)變量委托給它:
val name = "Kotlin".also { println("name 初始化") }
val lazyName by lazy { println("lazyName 初始化"); "Kotlin" }
val version = 2.also { println("version 初始化") }
val lazyVersion by lazy { println("lazyVersion 初始化"); 2 }
fun main() {
// 在運(yùn)行時(shí),name 就被初始化了
// 而委托給 Lazy 的 lazyName 沒(méi)有被初始化
// 在運(yùn)行時(shí),version 就被初始化了
// 只有在訪問(wèn)值時(shí),lazyVersion 才會(huì)被初始化
lazyVersion
}
name 初始化
version 初始化
lazyVersion 初始化
委托給另一個(gè)變量
此時(shí)被委托變量前需要加雙冒號(hào)::,事實(shí)上,::name會(huì)返回一個(gè)KMutableProperty0
二者的 getter 和 setter 實(shí)際上已經(jīng)綁定在一起了,當(dāng)其中一個(gè)的值改變,另一個(gè)也會(huì)跟著變。
var name: String = "K1"
fun main() {
var delegateName by ::name
// 打印 name 并改變 delegateName 也是同樣的結(jié)果
println(delegateName)
name = "K2"
print(delegateName)
}
K1
K2
不能將可變變量var委托給不可變變量val,因?yàn)関al沒(méi)有 setter。
val name: String = "K1"
fun main() {
// 這是錯(cuò)誤的
// var delegateName by ::name
}
自定義可委托類
得益于 IDEA 自動(dòng)補(bǔ)全,我們可以直接寫出委托關(guān)系var value by MyClass(),鼠標(biāo)懸停(或者光標(biāo)置于標(biāo)紅處,按鍵盤Alt+Enter),點(diǎn)擊創(chuàng)建getValue、setValue,并加以修改即可。其中,參數(shù)名可以自定義。
生成的nothing(第1個(gè)參數(shù))一般是叫thisRef,它的類型是該變量所有者的類型(例如某個(gè)類的成員變量,其所有者是該類)。 這里Nothing?則表示沒(méi)有所有者。對(duì)于其他類型,如果加了?,則所有變量都可以委托,如果不加,則只有變量的所有者為指定類型可以委托。
property中則包含了委托變量的屬性,例如property.name可以獲取到變量名。其類型必須為KProperty<*>。
getValue的返回值一般需要指明為所要獲取值的類型,這里把MyClass.value返回。 setValue傳入的第3個(gè)參數(shù)則是要賦的值,這里把值給MyClass.value
import kotlin.reflect.KProperty
class MyClass {
private var value = "MyClass"
operator fun getValue(thisRef: Nothing?, property: KProperty<*>): String {
println("getValue")
return value
}
operator fun setValue(thisRef: Nothing?, property: KProperty<*>, s: String) {
println("setValue")
value = s
}
}
fun main() {
var value by MyClass()
println(value)
value = "Hello"
print(value)
}
getValue
MyClass
setValue
getValue
Hello
柚子快報(bào)激活碼778899分享:Kotlin 委托
文章來(lái)源
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。