中階:物件
在本章中,您將透過探索物件宣告來擴展對類別的理解。這些知識將幫助您有效地管理專案中的行為。
物件宣告
在 Kotlin 中,您可以使用 物件宣告 來宣告只有單一實例的類別。從某種意義上說,您是同時宣告類別並建立該單一實例。當您想要建立一個類別作為程式的單一參考點或協調系統中的行為時,物件宣告會非常有用。
只有一個易於存取之實例的類別稱為 單例。
Kotlin 中的物件是 惰性 的,這表示它們僅在被存取時才建立。Kotlin 還確保所有物件都以執行緒安全的方式建立,因此您無需手動檢查。
要建立物件宣告,請使用 object
關鍵字:
object DoAuth {}
在您的 object
名稱之後,於以花括號 {}
定義的物件主體中添加任何屬性或成員函式。
物件不能有建構式,因此它們不像類別那樣有標頭。
例如,假設您想要建立一個名為 DoAuth
的物件,負責身分驗證:
object DoAuth {
fun takeParams(username: String, password: String) {
println("input Auth parameters = $username:$password")
}
}
fun main(){
// 物件在 takeParams() 函式被呼叫時建立
DoAuth.takeParams("coding_ninja", "N1njaC0ding!")
// input Auth parameters = coding_ninja:N1njaC0ding!
}
此物件有一個名為 takeParams
的成員函式,它接受 username
和 password
變數作為參數,並向控制台列印一個字串。DoAuth
物件僅在該函式首次被呼叫時建立。
物件可以繼承類別和介面。例如:
kotlininterface Auth { fun takeParams(username: String, password: String) } object DoAuth : Auth { override fun takeParams(username: String, password: String) { println("input Auth parameters = $username:$password") } }
資料物件
為了更容易列印物件宣告的內容,Kotlin 提供了 資料 物件。與您在入門教學中學到的資料類別類似,資料物件會自動附帶額外的成員函式:toString()
和 equals()
。
與資料類別不同,資料物件不會自動附帶
copy()
成員函式,因為它們只有一個無法複製的單一實例。
要建立資料物件,請使用與物件宣告相同的語法,但在其前面加上 data
關鍵字:
data object AppConfig {}
例如:
data object AppConfig {
var appName: String = "My Application"
var version: String = "1.0.0"
}
fun main() {
println(AppConfig)
// AppConfig
println(AppConfig.appName)
// My Application
}
伴隨物件
在 Kotlin 中,一個類別可以擁有一個物件:一個 伴隨 物件。每個類別只能有一個伴隨物件。伴隨物件僅在其類別首次被引用時建立。
在伴隨物件內宣告的任何屬性或函式都會在所有類別實例之間共享。
要在類別中建立伴隨物件,請使用與物件宣告相同的語法,但在其前面加上 companion
關鍵字:
companion object Bonger {}
伴隨物件不一定要有名稱。如果您未定義名稱,預設為
Companion
。
要存取伴隨物件的任何屬性或函式,請引用類別名稱。例如:
class BigBen {
companion object Bonger {
fun getBongs(nTimes: Int) {
repeat(nTimes) { print("BONG ") }
}
}
}
fun main() {
// 伴隨物件在類別首次被引用時建立。
BigBen.getBongs(12)
// BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG
}
此範例建立了一個名為 BigBen
的類別,其中包含一個名為 Bonger
的伴隨物件。該伴隨物件有一個名為 getBongs()
的成員函式,它接受一個整數,並根據該整數列印相同次數的 "BONG"
到控制台。
在 main()
函式中,getBongs()
函式透過引用類別名稱來呼叫。伴隨物件在此時建立。getBongs()
函式以參數 12
呼叫。
練習
練習 1
您經營一家咖啡店,並有一個追蹤顧客訂單的系統。請考慮以下程式碼並完成第二個資料物件的宣告,以便 main()
函式中的以下程式碼能成功執行:
interface Order {
val orderId: String
val customerName: String
val orderTotal: Double
}
data object OrderOne: Order {
override val orderId = "001"
override val customerName = "Alice"
override val orderTotal = 15.50
}
data object // Write your code here
fun main() {
// 列印每個資料物件的名稱
println("Order name: $OrderOne")
// Order name: OrderOne
println("Order name: $OrderTwo")
// Order name: OrderTwo
// 檢查訂單是否相同
println("Are the two orders identical? ${OrderOne == OrderTwo}")
// 這兩個訂單相同嗎? false
if (OrderOne == OrderTwo) {
println("The orders are identical.")
} else {
println("The orders are unique.")
// 訂單是獨特的。
}
println("Do the orders have the same customer name? ${OrderOne.customerName == OrderTwo.customerName}")
// 這些訂單有相同的顧客名稱嗎? false
}
範例解答
interface Order {
val orderId: String
val customerName: String
val orderTotal: Double
}
data object OrderTwo: Order {
override val orderId = "002"
override val customerName = "Bob"
override val orderTotal = 12.75
}
fun main() {
// 列印每個資料物件的名稱
println("Order name: $OrderOne")
// Order name: OrderOne
println("Order name: OrderTwo")
// Order name: OrderTwo
// 檢查訂單是否相同
println("Are the two orders identical? ${OrderOne == OrderTwo}")
// 這兩個訂單相同嗎? false
if (OrderOne == OrderTwo) {
println("The orders are identical.")
} else {
println("The orders are unique.")
// 訂單是獨特的。
}
println("Do the orders have the same customer name? ${OrderOne.customerName == OrderTwo.customerName}")
// 這些訂單有相同的顧客名稱嗎? false
}
練習 2
建立一個物件宣告,該物件繼承自 Vehicle
介面,以建立一個獨特的載具類型:FlyingSkateboard
。在您的物件中實作 name
屬性和 move()
函式,以便 main()
函式中的以下程式碼能成功執行:
interface Vehicle {
val name: String
fun move(): String
}
object // Write your code here
fun main() {
println("${FlyingSkateboard.name}: ${FlyingSkateboard.move()}")
// 飛行滑板:使用懸浮引擎在空中滑翔
println("${FlyingSkateboard.name}: ${FlyingSkateboard.fly()}")
// 飛行滑板:Woooooo
}
範例解答
interface Vehicle {
val name: String
fun move(): String
}
object FlyingSkateboard : Vehicle {
override val name = "Flying Skateboard"
override fun move() = "Glides through the air with a hover engine"
fun fly(): String = "Woooooooo"
}
fun main() {
println("${FlyingSkateboard.name}: ${FlyingSkateboard.move()}")
// 飛行滑板:使用懸浮引擎在空中滑翔
println("${FlyingSkateboard.name}: ${FlyingSkateboard.fly()}")
// 飛行滑板:Woooooo
}
練習 3
您有一個應用程式,想要記錄溫度。類別本身以攝氏度儲存資訊,但您也想提供一種簡單的方法來建立華氏度的實例。請完成資料類別,以便 main()
函式中的以下程式碼能成功執行:
提示
data class Temperature(val celsius: Double) {
val fahrenheit: Double = celsius * 9 / 5 + 32
// Write your code here
}
fun main() {
val fahrenheit = 90.0
val temp = Temperature.fromFahrenheit(fahrenheit)
println("${temp.celsius}°C is $fahrenheit °F")
// 32.22222222222222°C 是 90.0 °F
}
範例解答
data class Temperature(val celsius: Double) {
val fahrenheit: Double = celsius * 9 / 5 + 32
companion object {
fun fromFahrenheit(fahrenheit: Double): Temperature = Temperature((fahrenheit - 32) * 5 / 9)
}
}
fun main() {
val fahrenheit = 90.0
val temp = Temperature.fromFahrenheit(fahrenheit)
println("${temp.celsius}°C is $fahrenheit °F")
// 32.22222222222222°C 是 90.0 °F
}