iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0

object 關鍵字

如果只想用一個實例管理整個專案執行期間的一致性時,便可以使用object關鍵字定義一個單例(singleton),整個應用程式的執行期間內,就只會存在一個實例,即使再建立一次該類別的實例,得到的還是最初的類別。使用singleton的時機大致可歸類為下面三種情況:

  • 整個專案需要一個共享存取點、共享資料。
  • 創建一個物件需要耗費資源過多,如: 訪問I/O或資料庫等資源。
  • 工具類物件。

object的使用方式有三:

  • 物件宣告 object declaration
  • 伴生物件 companion object
  • 物件運算式 object expression

物件宣告 object declaration

使用object關鍵字:
物件宣告會自動實例化,所以不會有建構函數。
並且物件宣告不能當作表達式放在等號右邊賦值給變數。
引用物件的時候直接叫他名字就好

object MyObject {
    private const val HELLO_WORLD = "hello world"
    fun printContent() {
        println(HELLO_WORLD)
    }
}

fun main(){
    MyObject.printContent()
    //結果 : hello world
}

伴生物件 companion object

若想將一個物件的初始化關聯至一個類別實例,就可以考慮伴生物件,透過companion修飾符,就能宣告伴生物件。
一個類別只能有一個伴生物件。不管MyClass實例化幾次,都只會有一個伴生物件的實例。
伴生物件的名字可有可無,沒有名字的話就會以companion為預設的名稱。

class MyClass {
    companion object {
        fun load() = println("loading")
        init {
            println("initial")
        }
    }
}

fun main() {
    //呼叫load()函數無須產生MyClass的實例,直接像下面這樣呼叫即可。
    MyClass.load()
    //結果: 
    //initial
    //loading
    
   //實例化兩個MyClass : 可以看到伴生物件的初始化區塊只有執行一次。所以多產生MyClass實例也不會增加伴生物件的數量
    val c1 = MyClass()
    val c2 = MyClass()    
    println(c1 == c2 )
   
    //結果: 
    // initial
    // false   
}

由上面程式碼可以觀察到,伴生物件初始化的時機有:

  • 直接存取伴生物件某個函數或屬性的時候,就會觸發伴生物件初始化。
  • 當該類別實例化的時候,觸發該類別的伴生物件初始化。

物件表達式 object expression

有時候我們需要一個物件實例,但可能只需要使用一次好像也沒必要為它建立類別,那可以考慮匿名物件(anonymous objects),連名字都可以省了。
這個匿名物件仍然遵循object關鍵字的「只能存在一個實例」的原則。
但它的生命週期與作用範圍就會遠遠小於命名單例。並且初始化行為會依據它在哪裡被定義而影響,如果定義在獨立檔案中,物件表達式會立即初始化,如果定義在另一個類別,那麼類別初始化後才會初始化表達式。
物件表達式可以放在等號右邊賦值給變數。也可以當子類別去繼承父類別

  • 沒有父類別這樣寫:
fun main() {
    val myDemo =  object {
        val title = "demo"
        val content = "It's a object"
        override fun toString()= "$title : $content"
    }
    println(myDemo)
 //結果 : demo : It's a object
}
  • 當父類別需要參數的時候,當然是要滿足條件:
//父類別
open class A(x: Int) {
    public open val y: Int = x
}

fun main() {
    val ab = object : A(1) {
        override val y = 15
    }
    println(ab.y)  //15
}
  • 當匿名物件用作本地或private類型但不是inline聲明(函數或屬性)時,它的所有成員都可以通過此函數或屬性存取:
class C {
    private fun getObject() = object {
        val x: String = "x"
    }

    fun printX() {
        println(getObject().x) //x值可以透過getObject().x存取
    }
}

更多的細節請參考:kotlin文檔


上一篇
第22天 Kotlin小學堂(11) : 繼承
下一篇
第24天 Kotlin小學堂(13) : null安全與異常
系列文
新手向Android&Kotlin學習紀錄30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言