kotlin 學(xué)習(xí) (11)

對象表達(dá)式與對象聲明

有時候,我們需要創(chuàng)建一個對某個類做了輕微改動的類的對象,而不用為之顯式聲明新的子類。 Kotlin 用對象表達(dá)式對象聲明處理這種情況。

對象表達(dá)式

要創(chuàng)建一個繼承自某個(或某些)類型的匿名類的對象,我們會這么寫:

window.addMouseListener(object:MouseAdapter() {

overridefunmouseClicked(e:MouseEvent) {/*……*/}

?

overridefunmouseEntered(e:MouseEvent) {/*……*/}

})

如果超類型有一個構(gòu)造函數(shù),則必須傳遞適當(dāng)?shù)臉?gòu)造函數(shù)參數(shù)給它。 多個超類型可以由跟在冒號后面的逗號分隔的列表指定:

openclassA(x:Int) {

publicopenvaly:Int=x

}

?

interfaceB{/*……*/}

?

valab:A=object:A(1),B{

overridevaly=15

}

任何時候,如果我們只需要“一個對象而已”,并不需要特殊超類型,那么我們可以簡單地寫:

funfoo() {

valadHoc=object{

varx:Int=0

vary:Int=0

? ? }

print(adHoc.x+adHoc.y)

}

請注意,匿名對象可以用作只在本地和私有作用域中聲明的類型。如果你使用匿名對象作為公有函數(shù)的返回類型或者用作公有屬性的類型,那么該函數(shù)或?qū)傩缘膶?shí)際類型會是匿名對象聲明的超類型,如果你沒有聲明任何超類型,就會是?Any。在匿名對象中添加的成員將無法訪問。

classC{

// 私有函數(shù),所以其返回類型是匿名對象類型

privatefunfoo()=object{

valx:String="x"

? ? }

?

// 公有函數(shù),所以其返回類型是 Any

funpublicFoo()=object{

valx:String="x"

? ? }

?

funbar() {

valx1=foo().x// 沒問題

valx2=publicFoo().x// 錯誤:未能解析的引用“x”

? ? }

}

對象表達(dá)式中的代碼可以訪問來自包含它的作用域的變量。

funcountClicks(window:JComponent) {

varclickCount=0

varenterCount=0

?

window.addMouseListener(object:MouseAdapter() {

overridefunmouseClicked(e:MouseEvent) {

clickCount++

? ? ? ? }

?

overridefunmouseEntered(e:MouseEvent) {

enterCount++

? ? ? ? }

? ? })

// ……

}

對象聲明

單例模式在一些場景中很有用, 而 Kotlin(繼 Scala 之后)使單例聲明變得很容易:

objectDataProviderManager{

funregisterDataProvider(provider:DataProvider) {

// ……

? ? }

?

valallDataProviders:Collection<DataProvider>

get()=// ……

}

這稱為對象聲明。并且它總是在?object?關(guān)鍵字后跟一個名稱。 就像變量聲明一樣,對象聲明不是一個表達(dá)式,不能用在賦值語句的右邊。

對象聲明的初始化過程是線程安全的并且在首次訪問時進(jìn)行。

如需引用該對象,我們直接使用其名稱即可:

DataProviderManager.registerDataProvider(……)

這些對象可以有超類型:

objectDefaultListener:MouseAdapter() {

overridefunmouseClicked(e:MouseEvent) {……}

?

overridefunmouseEntered(e:MouseEvent) {……}

}

注意:對象聲明不能在局部作用域(即直接嵌套在函數(shù)內(nèi)部),但是它們可以嵌套到其他對象聲明或非內(nèi)部類中。

伴生對象

類內(nèi)部的對象聲明可以用?companion?關(guān)鍵字標(biāo)記:

classMyClass{

companionobjectFactory{

funcreate():MyClass=MyClass()

? ? }

}

該伴生對象的成員可通過只使用類名作為限定符來調(diào)用:

valinstance=MyClass.create()

可以省略伴生對象的名稱,在這種情況下將使用名稱?Companion:

classMyClass{

companionobject{ }

}

?

valx=MyClass.Companion

其自身所用的類的名稱(不是另一個名稱的限定符)可用作對該類的伴生對象 (無論是否具名)的引用:

classMyClass1{

companionobjectNamed{ }

}

?

valx=MyClass1

?

classMyClass2{

companionobject{ }

}

?

valy=MyClass2

請注意,即使伴生對象的成員看起來像其他語言的靜態(tài)成員,在運(yùn)行時他們?nèi)匀皇钦鎸?shí)對象的實(shí)例成員,而且,例如還可以實(shí)現(xiàn)接口:

interfaceFactory<T>{

funcreate():T

}

?

classMyClass{

companionobject:Factory<MyClass>{

overridefuncreate():MyClass=MyClass()

? ? }

}

?

valf:Factory<MyClass>=MyClass

當(dāng)然,在 JVM 平臺,如果使用?@JvmStatic?注解,你可以將伴生對象的成員生成為真正的靜態(tài)方法和字段。更詳細(xì)信息請參見Java 互操作性一節(jié) 。

對象表達(dá)式和對象聲明之間的語義差異

對象表達(dá)式和對象聲明之間有一個重要的語義差別:

對象表達(dá)式是在使用他們的地方立即執(zhí)行(及初始化)的;

對象聲明是在第一次被訪問到時延遲初始化的;

伴生對象的初始化是在相應(yīng)的類被加載(解析)時,與 Java 靜態(tài)初始化器的語義相匹配。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 面向?qū)ο缶幊蹋∣OP) 在前面的章節(jié)中,我們學(xué)習(xí)了Kotlin的語言基礎(chǔ)知識、類型系統(tǒng)、集合類以及泛型相關(guān)的知識。...
    Tenderness4閱讀 4,607評論 1 6
  • 原文鏈接:https://github.com/EasyKotlin 值就是函數(shù),函數(shù)就是值。所有函數(shù)都消費(fèi)函數(shù),...
    JackChen1024閱讀 6,334評論 1 17
  • val和varval(來自value)——不可變引用。使用val使用val聲明的變量不能在初始化之后再次賦值。它對...
    WangSins閱讀 459評論 0 0
  • 函數(shù)和對象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念。通過函數(shù)可以封裝任意多條語句,而且...
    道無虛閱讀 4,944評論 0 5
  • 她不知道要經(jīng)歷多少才能領(lǐng)悟愛的真諦,一直以來他離開以后她就一個人走走停停,難過了就自己和著發(fā)燙的洗澡水狠狠的哭,開...
    溫儀閱讀 484評論 0 1

友情鏈接更多精彩內(nèi)容