以下是 Kotlin 屬性(Property) 的基礎概念:var 和 val 的區別、自訂存取器、延遲初始化(lateinit 和 lazy)、const 常數等。
1. 基本概念#
定義屬性#
Kotlin 中的屬性可以用以下兩種方式定義:
var:可變屬性(可讀寫)。val:不可變屬性(唯讀)。
範例:var 和 val#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| class Person {
var name: String = "Default Name" // 可讀寫
val age: Int = 18 // 唯讀
}
fun main() {
val person = Person()
println(person.name) // 輸出:Default Name
person.name = "Alice"
println(person.name) // 輸出:Alice
// person.age = 20 // 錯誤:`val` 屬性不可修改
println(person.age) // 輸出:18
}
|
2. 預設 getter 和 setter#
Kotlin 中,所有屬性都自動生成預設的 getter 和 setter:
val(不可變屬性):僅有 getter。var(可變屬性):同時擁有 getter 和 setter。
範例:#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| class Person {
var name: String = "Default Name" // 自動生成 getter 和 setter
val age: Int = 18 // 只有 getter
}
fun main() {
val person = Person()
// 使用預設的 getter
println(person.name) // 輸出:Default Name
println(person.age) // 輸出:18
// 使用預設的 setter
person.name = "Alice"
println(person.name) // 輸出:Alice
// person.age = 25 // 錯誤:`val` 屬性無法修改
}
|
3. 自訂 getter 和 setter#
Kotlin 允許自訂屬性的 getter 和 setter,用於在屬性讀取或寫入時執行額外邏輯。
1
2
3
4
5
| var 屬性名稱: 資料型別 = 初始值
get() = // 自訂 getter
set(value) {
// 自訂 setter
}
|
範例:#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| class Person {
var name: String = "Default Name"
get() {
println("Getter called for name")
return field // 使用 field 取得屬性值
}
set(value) {
println("Setter called with value: $value")
field = value // 使用 field 設定屬性值
}
var age: Int = 18
set(value) {
if (value >= 0) {
field = value // 僅允許非負數
} else {
println("Age cannot be negative")
}
}
}
fun main() {
val person = Person()
// 測試自訂 getter 和 setter
println(person.name) // 輸出:Getter called for name -> Default Name
person.name = "Alice" // 輸出:Setter called with value: Alice
println(person.name) // 輸出:Getter called for name -> Alice
person.age = -5 // 輸出:Age cannot be negative
println(person.age) // 輸出:18
}
|
關鍵字:field 的作用#
field 是後備欄位(Backing Field),儲存屬性的實際值。- 當屬性有自訂的
getter 和 setter 時,需用 field 存取或設定屬性的內部值。
為什麼需要 field?#
如果在 getter 或 setter 中直接使用屬性名稱(如 name),會導致遞迴呼叫自己,最終導致程式崩潰。
錯誤範例:沒有使用 field#
1
2
3
4
5
6
7
8
9
| class Person {
var name: String = "Default Name"
get() {
return name // 錯誤:導致遞迴呼叫
}
set(value) {
name = value // 錯誤:導致遞迴呼叫
}
}
|
正確範例:使用 field#
1
2
3
4
5
6
7
| class Person {
var name: String = "Default Name"
get() = field // 正確使用
set(value) {
field = value // 正確使用
}
}
|
4. 計算屬性#
計算屬性不需要存儲數據,每次存取時動態計算值。計算屬性僅有 getter,無 setter。
範例:#
1
2
3
4
5
6
7
8
9
| class Rectangle(val width: Int, val height: Int) {
val area: Int
get() = width * height // 計算屬性值
}
fun main() {
val rectangle = Rectangle(5, 10)
println("Area: ${rectangle.area}") // 輸出:Area: 50
}
|
5. 延遲初始化屬性#
Kotlin 提供兩種方式延遲初始化屬性:lateinit 和 lazy。
5.1 lateinit#
- 用於延遲初始化可變屬性(
var)。 - 必須檢查是否已初始化,否則會拋出例外。
- 常用於類別初始化時無法確定值的情況。
範例:#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| class Person {
lateinit var name: String
fun initializeName(value: String) {
name = value
}
fun printName() {
if (::name.isInitialized) {
println("Name: $name")
} else {
println("Name is not initialized")
}
}
}
fun main() {
val person = Person()
person.printName() // 輸出:Name is not initialized
person.initializeName("Alice")
person.printName() // 輸出:Name: Alice
}
|
5.2 lazy#
- 用於延遲初始化唯讀屬性(
val)。 - 第一次存取時執行初始化邏輯,且僅執行一次。
範例:#
1
2
3
4
5
6
7
8
9
10
11
12
13
| class Person {
val greeting: String by lazy {
println("Initializing greeting...")
"Hello, Kotlin!"
}
}
fun main() {
val person = Person()
println("Before accessing greeting")
println(person.greeting) // 第一次存取時初始化,輸出:Initializing greeting... -> Hello, Kotlin!
println(person.greeting) // 輸出:Hello, Kotlin!
}
|
6. 常數(const)#
const 修飾的屬性#
- 必須在
object 或 companion object 中定義。 - 必須是基本型別(
String、Int 等)。 - 編譯時期常數,無法修改。
範例:#
1
2
3
4
5
6
7
8
9
| class Constants {
companion object {
const val MAX_USERS = 100
}
}
fun main() {
println("Max users: ${Constants.MAX_USERS}") // 輸出:Max users: 100
}
|
7. 屬性的可見性修飾符#
Kotlin 提供以下可見性修飾符,用於控制屬性的存取範圍:
public(預設):所有地方可見。private:僅在類別內部可見。protected:在類別及其子類別中可見。internal:在同一模組內可見。
範例:可見性修飾符#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| open class Animal {
private var privateProp = "Private"
protected var protectedProp = "Protected"
internal var internalProp = "Internal"
public var publicProp = "Public"
fun printProps() {
println("$privateProp, $protectedProp, $internalProp, $publicProp")
}
}
class Dog : Animal() {
fun printDogProps() {
// println(privateProp) // 錯誤:private 無法存取
println(protectedProp) // 可存取
println(internalProp) // 可存取
println(publicProp) // 可存取
}
}
fun main() {
val dog = Dog()
dog.printDogProps()
// dog.privateProp // 錯誤:無法存取 private 屬性
// dog.protectedProp // 錯誤:無法存取 protected 屬性
println(dog.publicProp) // 輸出:Public
}
|
8. 擴展屬性#
Kotlin 支援為現有型別定義擴展屬性。
範例:#
1
2
3
4
5
6
7
| val String.wordCount: Int
get() = this.split(" ").size
fun main() {
val text = "Kotlin is awesome"
println("Word count: ${text.wordCount}") // 輸出:Word count: 3
}
|
Reference#
https://kotlinlang.org/docs/properties.html