鍍金池/ 教程/ Android/ Kotlin對(duì)象表達(dá)式和對(duì)象聲明
Kotlin內(nèi)聯(lián)函數(shù)
Kotlin開(kāi)發(fā)環(huán)境設(shè)置(Eclipse)
Kotlin調(diào)用Java代碼
Kotlin使用Ant
Kotlin編譯器插件
Kotlin相等性
Kotlin JavaScript模塊
編寫Kotlin代碼文檔
Kotlin返回和跳轉(zhuǎn)
Kotlin異常處理
Kotlin可見(jiàn)性修飾符
Kotlin委托
Kotlin委托屬性
Kotlin編碼約定/編碼風(fēng)格
Kotlin基礎(chǔ)語(yǔ)法
使用Kotlin進(jìn)行服務(wù)器端開(kāi)發(fā)
Kotlin接口
Kotlin反射
Kotlin類型別名
Kotlin枚舉類
Kotlin當(dāng)前版本是多少?
Kotlin注解處理工具
Kotlin類型的檢查與轉(zhuǎn)換
Kotlin屬性和字段
Kotlin類型安全的構(gòu)建器
Kotlin相比Java語(yǔ)言有哪些優(yōu)點(diǎn)?
Kotlin JavaScript反射
Kotlin 是什么?
Kotlin泛型
Kotlin慣用語(yǔ)法
Kotlin與OSGi
Kotlin數(shù)據(jù)類型
Kotlin是面向?qū)ο筮€是函數(shù)式語(yǔ)言?
Kotlin動(dòng)態(tài)類型
Kotlin協(xié)程
Kotlin操作符符重載
Kotlin使用Gradle
Kotlin密封類
Kotlin兼容性
Kotlin集合
Kotlin調(diào)用JavaScript
Kotlin null值安全
Kotlin函數(shù)
Kotlin開(kāi)發(fā)環(huán)境設(shè)置(IntelliJ IDEA)
Kotlin嵌套類
Kotlin控制流程
Kotlin和Java語(yǔ)言比較
Kotlin 與 Java 語(yǔ)言兼容嗎?
Kotlin教程
Kotlin類和繼承
Kotlin對(duì)象表達(dá)式和對(duì)象聲明
JavaScript中調(diào)用Kotlin
Kotlin區(qū)間/范圍
Kotlin數(shù)據(jù)類
Kotlin lambda表達(dá)式
Kotlin是免費(fèi)的嗎?
Kotlin包
使用Kotlin進(jìn)行Android開(kāi)發(fā)
在Java中調(diào)用Kotlin代碼
Kotlin this表達(dá)式
使用Kotlin進(jìn)行JavaScript開(kāi)發(fā)
Kotlin擴(kuò)展
Kotlin解構(gòu)聲明
Kotlin注解
Kotlin使用Maven

Kotlin對(duì)象表達(dá)式和對(duì)象聲明

對(duì)象表達(dá)式和對(duì)象聲明

有時(shí)候,我們需要?jiǎng)?chuàng)建一個(gè)對(duì)某個(gè)類做了輕微改動(dòng)的類的對(duì)象,而不用為之顯式聲明新的子類。
Java 用匿名內(nèi)部類 處理這種情況。
Kotlin 用對(duì)象表達(dá)式對(duì)象聲明對(duì)這個(gè)概念稍微概括了下。

對(duì)象表達(dá)式

要?jiǎng)?chuàng)建一個(gè)繼承自某個(gè)(或某些)類型的匿名類的對(duì)象,我們會(huì)這么寫:

window.addMouseListener(object : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        // ……
    }

    override fun mouseEntered(e: MouseEvent) {
        // ……
    }
})

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

open class A(x: Int) {
    public open val y: Int = x
}

interface B {……}

val ab: A = object : A(1), B {
    override val y = 15
}

任何時(shí)候,如果我們只需要“一個(gè)對(duì)象而已”,并不需要特殊超類型,那么我們可以簡(jiǎn)單地寫:

fun foo() {
    val adHoc = object {
        var x: Int = 0
        var y: Int = 0
    }
    print(adHoc.x + adHoc.y)
}

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

class C {
    // 私有函數(shù),所以其返回類型是匿名對(duì)象類型
    private fun foo() = object {
        val x: String = "x"
    }

    // 公有函數(shù),所以其返回類型是 Any
    fun publicFoo() = object {
        val x: String = "x"
    }

    fun bar() {
        val x1 = foo().x        // 沒(méi)問(wèn)題
        val x2 = publicFoo().x  // 錯(cuò)誤:未能解析的引用“x”
    }
}

就像 Java 匿名內(nèi)部類一樣,對(duì)象表達(dá)式中的代碼可以訪問(wèn)來(lái)自包含它的作用域的變量。
(與 Java 不同的是,這不僅限于 final 變量。)

fun countClicks(window: JComponent) {
    var clickCount = 0
    var enterCount = 0

    window.addMouseListener(object : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            clickCount++
        }

        override fun mouseEntered(e: MouseEvent) {
            enterCount++
        }
    })
    // ……
}

對(duì)象聲明

單例模式是一種非常有用的模式,而 Kotlin(繼 Scala 之后)使單例聲明變得很容易:

object DataProviderManager {
    fun registerDataProvider(provider: DataProvider) {
        // ……
    }

    val allDataProviders: Collection<DataProvider>
        get() = // ……
}

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

要引用該對(duì)象,我們直接使用其名稱即可:

DataProviderManager.registerDataProvider(……)

這些對(duì)象可以有超類型:

object DefaultListener : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        // ……
    }

    override fun mouseEntered(e: MouseEvent) {
        // ……
    }
}

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

伴生對(duì)象

類內(nèi)部的對(duì)象聲明可以用 companion{: .keyword } 關(guān)鍵字標(biāo)記:

class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}

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

val instance = MyClass.create()

可以省略伴生對(duì)象的名稱,在這種情況下將使用名稱 Companion

class MyClass {
    companion object {
    }
}

val x = MyClass.Companion

請(qǐng)注意,即使伴生對(duì)象的成員看起來(lái)像其他語(yǔ)言的靜態(tài)成員,在運(yùn)行時(shí)他們
仍然是真實(shí)對(duì)象的實(shí)例成員,而且,例如還可以實(shí)現(xiàn)接口:

interface Factory<T> {
    fun create(): T
}


class MyClass {
    companion object : Factory<MyClass> {
        override fun create(): MyClass = MyClass()
    }
}

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

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

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

  • 對(duì)象表達(dá)式是在使用他們的地方立即執(zhí)行(及初始化)的
  • 對(duì)象聲明是在第一次被訪問(wèn)到時(shí)延遲初始化的
  • 伴生對(duì)象的初始化是在相應(yīng)的類被加載(解析)時(shí),與 Java 靜態(tài)初始化器的語(yǔ)義相匹配

上一篇:Kotlin使用Ant下一篇:Kotlin擴(kuò)展