Kotlin 對象表達式和對象聲明 對象表達式和對象聲明之間的語義差異 對象表達式 對象聲明 伴生對象 對象表達式和對象聲明之間的語義差異

Kotlin 用對象表達式和對象聲明來實現創建一個 對某個類做了輕微改動 的類的對象,且不需要去聲明一個新的子類。

對象表達式和對象聲明之間的語義差異

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

  • 對象表達式是在使用他們的地方立即執行的
  • 對象聲明是在第一次被訪問到時延遲初始化的
  • 伴生對象的初始化是在相應的類被加載(解析)時,與 Java 靜態初始化器的語義相匹配

對象表達式

通過對象表達式實現一個匿名內部類的對象用於方法的參數中,其實就是類似java中的new接口{}。

btnOperator.setOnClickListener(object : View.OnClickListener{
            override fun onClick(v: View?) {

            }
        })

簡化後

btnOperator.setOnClickListener { }

對象可以繼承於某個基類,或者實現其他接口:
如果超類型有一個構造函數,則必須傳遞參數給它。多個超類型和接口可以用逗號分隔。

open class A(x: Int) {
    open val y: Int = x
}
interface B 
val cc: A = object : A(1),B {
    override val y = 15
}
通過對象表達式可以越過類的定義直接得到一個對象:
        val site = object {
            var name: String = "zhongjh"
            var gender: String = "男"
        }
        println(site.name)
        println(site.gender)
私有函數和公有函數創建對象

請注意,匿名對象可以用作只在本地和私有作用域中聲明的類型。如果你沒有聲明任何超類型,就會是 Any。在匿名對象 中添加的成員將無法訪問。

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

    // 這個跟上一個是差不多一樣的哦
    private val foo = object {
        val x: String = "x"
        val y: String = "y"
    }

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

        val x1 = foo().x        // 沒問題
        val y1 = foo().y        // 沒問題
        val x2 = publicFoo()  // val x2 = publicFoo().x 錯誤:未能解析的引用“x”
        val x3 = foo.x
在對象表達中可以方便的訪問到作用域中的其他變量:
var clickCount = 0

btnOperator.setOnClickListener {
    clickCount++;
}

對象聲明

Kotlin 使用 object 關鍵字來聲明一個對象。
Kotlin 中我們可以方便的通過對象聲明來獲得一個單例。是的,都是同一個數據,讓我們看看下面兩個例子

    object DataProviderManager {
        const val name = "name"
        fun registerDataProvider() {
        }
    }
        DataProviderManager.registerDataProvider()
        DataProviderManager.name
    object Site {
        var url:String = ""
        val name: String = "zhongjh"
    }
        val s1 = Site
        val s2 = Site
        s1.url = "www.zhongjh.com"
        tvContent.append("${s1.url}\n")
        tvContent.append("${s2.url}\n")

所以他們分別輸出的結果都是一樣:


對象聲明有以下兩點不能訪問:

  • 內部對象不能直接訪問到外部類的方法和變量。
  • 對象聲明後不能通過外部類的實例訪問到該對象,而只能通過類名來訪問。
    class ZhongJH {
        var name = "zhongjh"
        object DeskTop{
            var url = "www.zhongjh.com"
            fun showName(){
//                print{"desk legs $name"} // 錯誤,不能訪問到外部類的方法和變量
            }
        }
    }
        var zhongjh = ZhongJH()
//        zhongjh.DeskTop.url  // 錯誤,不能通過外部類的實例訪問到該對象
        ZhongJH.DeskTop.url  // 正確

伴生對象

類內部的對象聲明可以用 companion 關鍵字標記,這樣它就與外部類關聯在一起,我們就可以直接通過外部類訪問到對象的內部元素。

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

// 訪問到對象的內部元素
val instance = MyClass.create()   

我們可以省略掉該對象的對象名,然後使用 Companion 替代需要聲明的對象名:

class MyClass {
    companion object {
    }
}

val x = MyClass.Companion

注意:一個類裏面只能聲明一個內部關聯對象,即關鍵字 companion 只能使用一次。

請伴生對象的成員看起來像其他語言的靜態成員,但在運行時他們仍然是真實對象的實例成員。例如還可以實現接口:

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


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

對象表達式和對象聲明之間的語義差異

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

  • 對象表達式是在使用他們的地方立即執行的
  • 對象聲明是在第一次被訪問到時延遲初始化的
  • 伴生對象的初始化是在相應的類被加載(解析)時,與 Java 靜態初始化器的語義相匹配
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章