前言
kotlin官網(wǎng)和kotlin教程學(xué)習(xí)教程的筆記孕蝉。
背景
有時(shí)我們需要?jiǎng)?chuàng)建一個(gè)對(duì)象, 這個(gè)對(duì)象在某個(gè)類(lèi)的基礎(chǔ)上略做修改, 但又不希望僅僅為了這一點(diǎn)點(diǎn)修改就明 確地聲明一個(gè)新類(lèi). Java 通過(guò) 匿名內(nèi)部類(lèi)(anonymous inner class) 來(lái)解決這種問(wèn)題. Kotlin 使用 對(duì)象表達(dá) 式(object expression) 和 對(duì)象聲明(object declaration), 對(duì)這個(gè)概念略做了一點(diǎn)泛化.
一问顷、對(duì)象表達(dá)式
類(lèi)似匿名內(nèi)部類(lèi)
1. 通過(guò)對(duì)象表達(dá)式實(shí)現(xiàn)一個(gè)匿名內(nèi)部類(lèi)的對(duì)象用于方法的參數(shù)中
recyclerview.addOnScrollListener(object :RecyclerView.OnScrollListener(){
})
textView.setOnClickListener(object :View.OnClickListener{
override fun onClick(p0: View?) {
}
})
**2.對(duì)象可以繼承于某個(gè)基類(lèi)饱亿,或者實(shí)現(xiàn)其他接口 **
open class A {}
interface B {}
val ab = object : A(), B {}
如果, 我們 “只需要對(duì)象”, 而不需要繼承任何有價(jià)值的基類(lèi)
val ab = object{
val a=0
val b=1
}
println(ab.a + ab.b)
3. 注意
匿名對(duì)象可以用作只在本地和私有作用域中聲明的類(lèi)型蕉扮。如果你使用匿名對(duì)象作為公有函數(shù)的返回類(lèi)型或者用作公有屬性的類(lèi)型滩租,那么該函數(shù)或?qū)傩缘膶?shí)際類(lèi)型會(huì)是匿名對(duì)象聲明的超類(lèi)型探膊,如果你沒(méi)有聲明任何超類(lèi)型杠愧,就會(huì)是 Any。在匿名對(duì)象中添加的成員將無(wú)法訪問(wèn)逞壁。
class User {
//私有函數(shù)流济,所以其返回類(lèi)型是匿名對(duì)象類(lèi)型
private fun foo() = object {
val x = "x"
}
//公有函數(shù),所以其返回類(lèi)型是 Any
fun pfoo() = object {
val x = "px"
}
//返回類(lèi)型是Any腌闯,則無(wú)法訪問(wèn)匿名對(duì)象中的成員
private fun afoo(): Any = object {
val x = "x"
}
fun check() {
val x1 = foo().x //ok
val x2 = pfoo().x //unresolved 錯(cuò)誤
val x3=afoo().x //unresolved 錯(cuò)誤
}
}
二绳瘟、對(duì)象聲明
類(lèi)似單例
- Kotlin中使用object關(guān)鍵字來(lái)聲明一個(gè)對(duì)象,因此可以方便的聲明一個(gè)單例:
object Site {
var url: String = ""
val name: String = ""
fun foo() {}
}
fun main(args: Array<String>) {
val s1 = Site
val s2 = Site
s1.url = "www.kotlin.com"
println(s1.url) // 輸出 www.kotlin.com
println(s2.url) // 輸出 www.kotlin.com
}
- 當(dāng)對(duì)象聲明在一個(gè)類(lèi)的內(nèi)部
class User {
val name = "user"
object Site {
var url: String = ""
fun foo() {
val c = name //錯(cuò)誤绑嘹,不能訪問(wèn)到外部類(lèi)的方法和變量
}
}
}
fun main(args: Array<String>) {
var s1 = User.Site //ok
var s2 = User().Site //錯(cuò)誤稽荧,不能通過(guò)外部里的實(shí)例訪問(wèn)到該對(duì)象
}
三、同伴對(duì)象
還記得擴(kuò)展函數(shù)與擴(kuò)展屬性這一節(jié)中工腋,我們引入了同伴對(duì)象么姨丈?這里在詳細(xì)的說(shuō)明一下,順便知識(shí)回顧
class User {
companion object { //同伴對(duì)象
fun foo(){ }
}
}
User.Companion.create() //默認(rèn)命名的調(diào)用
User.create() //可以忽略名稱(chēng)調(diào)用
當(dāng)然我們也可以給同伴對(duì)象命名
class User {
companion object Factory{
fun create():User= User()
}
}
User.Factory.create() //命名后的調(diào)用
User.create() //忽略名稱(chēng)的調(diào)用
注意, 雖然同伴對(duì)象的成員看起來(lái)很像其他語(yǔ)言中的類(lèi)的靜態(tài)成員(static member), 但在運(yùn)行時(shí)期, 這些成員仍然是真實(shí)對(duì)象的實(shí)例的成員, 它們與靜態(tài)成員是不同的
例如, 它可以實(shí)現(xiàn)接口:
interface B{
fun create():User
}
class User {
companion object :B{
override fun create():User= User()
}
}
User.create()
四擅腰、對(duì)象表達(dá)式與對(duì)象聲明在語(yǔ)義上的區(qū)別
- 對(duì)象聲明是 延遲(lazily) 初始化的, 只會(huì)在首次訪問(wèn)時(shí)才會(huì)初始化
- 對(duì)象表達(dá)式則會(huì)在使用處 立即 執(zhí)行(并且初始化)