如果只想用一個實例管理整個專案執行期間的一致性時,便可以使用object關鍵字定義一個單例(singleton),整個應用程式的執行期間內,就只會存在一個實例,即使再建立一次該類別的實例,得到的還是最初的類別。使用singleton的時機大致可歸類為下面三種情況:
使用object關鍵字:
物件宣告會自動實例化,所以不會有建構函數。
並且物件宣告不能當作表達式放在等號右邊賦值給變數。
引用物件的時候直接叫他名字就好
object MyObject {
private const val HELLO_WORLD = "hello world"
fun printContent() {
println(HELLO_WORLD)
}
}
fun main(){
MyObject.printContent()
//結果 : hello world
}
若想將一個物件的初始化關聯至一個類別實例,就可以考慮伴生物件,透過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
}
由上面程式碼可以觀察到,伴生物件初始化的時機有:
有時候我們需要一個物件實例,但可能只需要使用一次好像也沒必要為它建立類別,那可以考慮匿名物件(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
}
class C {
private fun getObject() = object {
val x: String = "x"
}
fun printX() {
println(getObject().x) //x值可以透過getObject().x存取
}
}
更多的細節請參考:kotlin文檔