類別
Kotlin 支援物件導向程式設計,其中包含類別與物件。物件對於在程式中儲存資料非常有用。 類別允許您宣告物件的一組特性。當您從類別建立物件時,可以節省時間與精力,因為您不必每次都宣告這些特性。
若要宣告類別,請使用 class
關鍵字:
class Customer
屬性
類別物件的特性可以在屬性中宣告。您可以為類別宣告屬性:
- 在類別名稱後的括號
()
內。
class Contact(val id: Int, var email: String)
- 在由大括號
{}
定義的類別主體內。
class Contact(val id: Int, var email: String) {
val category: String = ""
}
我們建議您將屬性宣告為唯讀 (val
),除非在建立類別實例後需要變更它們。
您可以在括號內宣告不帶 val
或 var
的屬性,但這些屬性在建立實例後將無法存取。
NOTE
括號
()
中包含的內容稱為類別標頭 (class header)。在宣告類別屬性時,您可以使用 尾隨逗號 (trailing comma)。
如同函數參數一樣,類別屬性可以有預設值:
class Contact(val id: Int, var email: String = "[email protected]") {
val category: String = "work"
}
建立實例
若要從類別建立物件,您可以使用建構函式 (constructor) 宣告一個類別實例 (instance)。
預設情況下,Kotlin 會自動建立一個帶有類別標頭中宣告的參數的建構函式。
例如:
class Contact(val id: Int, var email: String)
fun main() {
val contact = Contact(1, "[email protected]")
}
在此範例中:
Contact
是一個類別。contact
是Contact
類別的實例。id
和email
是屬性。id
和email
與預設建構函式一起用於建立contact
。
Kotlin 類別可以有多個建構函式,包括您自行定義的。若要了解如何宣告多個建構函式,請參閱 建構函式 (Constructors)。
存取屬性
若要存取實例的屬性,請在實例名稱後加上句點 .
,然後寫上屬性名稱:
class Contact(val id: Int, var email: String)
fun main() {
val contact = Contact(1, "[email protected]")
// 印出屬性 email 的值
println(contact.email)
// [email protected]
// 更新屬性 email 的值
contact.email = "[email protected]"
// 印出屬性 email 的新值
println(contact.email)
// [email protected]
}
TIP
若要將屬性值串接到字串中,可以使用字串範本 ($
)。
例如:
println("Their email address is: ${contact.email}")
成員函數
除了將屬性宣告為物件特性的一部分之外,您還可以使用成員函數定義物件的行為。
在 Kotlin 中,成員函數必須在類別主體內宣告。若要在實例上呼叫成員函數,請在實例名稱後加上句點 .
,然後寫上函數名稱。例如:
class Contact(val id: Int, var email: String) {
fun printId() {
println(id)
}
}
fun main() {
val contact = Contact(1, "[email protected]")
// 呼叫成員函數 printId()
contact.printId()
// 1
}
資料類別
Kotlin 具有資料類別 (data classes),它們對於儲存資料特別有用。資料類別具有與一般類別相同的功能,但它們會自動提供額外的成員函數。這些成員函數讓您可以輕鬆地將實例印出為可讀的輸出、比較類別的實例、複製實例等等。由於這些函數是自動可用的,因此您無需花時間為每個類別編寫相同的樣板程式碼。
若要宣告資料類別,請使用 data
關鍵字:
data class User(val name: String, val id: Int)
資料類別最有用的一些預定義成員函數包括:
函數 | 描述 |
---|---|
toString() | 將類別實例及其屬性印出為可讀的字串。 |
equals() 或 == | 比較類別的實例。 |
copy() | 透過複製另一個類別實例來建立一個新實例,可選擇性地變更部分屬性。 |
請參閱以下章節,以了解如何使用每個函數的範例:
印為字串
若要將類別實例印為可讀的字串,您可以明確呼叫 toString()
函數,或使用印出函數 (println()
和 print()
),它們會自動為您呼叫 toString()
:
data class User(val name: String, val id: Int)
fun main() {
val user = User("Alex", 1)
// 自動使用 toString() 函數,使輸出易於閱讀
println(user)
// User(name=Alex, id=1)
}
這在偵錯或建立日誌時特別有用。
比較實例
若要比較資料類別實例,請使用等於運算子 ==
:
data class User(val name: String, val id: Int)
fun main() {
val user = User("Alex", 1)
val secondUser = User("Alex", 1)
val thirdUser = User("Max", 2)
// 比較 user 與 secondUser
println("user == secondUser: ${user == secondUser}")
// user == secondUser: true
// 比較 user 與 thirdUser
println("user == thirdUser: ${user == thirdUser}")
// user == thirdUser: false
}
複製實例
若要建立資料類別實例的精確副本,請在該實例上呼叫 copy()
函數。
若要建立資料類別實例的副本並變更部分屬性,請在該實例上呼叫 copy()
函數並將替換值作為函數參數新增到屬性中。
例如:
data class User(val name: String, val id: Int)
fun main() {
val user = User("Alex", 1)
// 建立 user 的精確副本
println(user.copy())
// User(name=Alex, id=1)
// 建立 user 的副本,並將 name 設為 "Max"
println(user.copy("Max"))
// User(name=Max, id=1)
// 建立 user 的副本,並將 id 設為 3
println(user.copy(id = 3))
// User(name=Alex, id=3)
}
建立實例的副本比修改原始實例更安全,因為依賴原始實例的任何程式碼都不會受到副本及其操作的影響。
有關資料類別的更多資訊,請參閱 資料類別 (Data classes)。
本教學的最後一章是關於 Kotlin 的 Null 安全 (Null safety)。
練習
練習 1
定義一個資料類別 Employee
,其中包含兩個屬性:一個用於姓名,另一個用於薪水。請確保薪水屬性是可變的,否則您將在年底無法獲得加薪!main
函數展示了如何使用此資料類別。
|---|---|
// Write your code here
fun main() {
val emp = Employee("Mary", 20)
println(emp)
emp.salary += 10
println(emp)
}
|---|---|
data class Employee(val name: String, var salary: Int)
fun main() {
val emp = Employee("Mary", 20)
println(emp)
emp.salary += 10
println(emp)
}
練習 2
宣告此程式碼編譯所需的額外資料類別。
|---|---|
data class Person(val name: Name, val address: Address, val ownsAPet: Boolean = true)
// Write your code here
// data class Name(...)
fun main() {
val person = Person(
Name("John", "Smith"),
Address("123 Fake Street", City("Springfield", "US")),
ownsAPet = false
)
}
|---|---|
data class Person(val name: Name, val address: Address, val ownsAPet: Boolean = true)
data class Name(val first: String, val last: String)
data class Address(val street: String, val city: City)
data class City(val name: String, val countryCode: String)
fun main() {
val person = Person(
Name("John", "Smith"),
Address("123 Fake Street", City("Springfield", "US")),
ownsAPet = false
)
}
練習 3
若要測試您的程式碼,您需要一個可以建立隨機員工的產生器。定義一個 RandomEmployeeGenerator
類別,其中包含固定的潛在姓名列表(在類別主體內)。配置類別的最低和最高薪水(在類別標頭內)。在類別主體中,定義 generateEmployee()
函數。main
函數再次展示了如何使用此類別。
|---|---|
import kotlin.random.Random
data class Employee(val name: String, var salary: Int)
// Write your code here
fun main() {
val empGen = RandomEmployeeGenerator(10, 30)
println(empGen.generateEmployee())
println(empGen.generateEmployee())
println(empGen.generateEmployee())
empGen.minSalary = 50
empGen.maxSalary = 100
println(empGen.generateEmployee())
}
|---|---|
import kotlin.random.Random
data class Employee(val name: String, var salary: Int)
class RandomEmployeeGenerator(var minSalary: Int, var maxSalary: Int) {
val names = listOf("John", "Mary", "Ann", "Paul", "Jack", "Elizabeth")
fun generateEmployee() =
Employee(names.random(),
Random.nextInt(from = minSalary, until = maxSalary))
}
fun main() {
val empGen = RandomEmployeeGenerator(10, 30)
println(empGen.generateEmployee())
println(empGen.generateEmployee())
println(empGen.generateEmployee())
empGen.minSalary = 50
empGen.maxSalary = 100
println(empGen.generateEmployee())
}