Kotlin 属性关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的属性系统提供了一种简洁的方式来管理类状态。property
概念用内置的访问器替换了字段。本教程通过实际例子深入探讨属性。
基本定义
在 Kotlin 中,属性是一个类成员,它将字段与访问器结合起来。属性会自动生成 getter 和 setter。它们可以使用 val
(只读)或 var
(可变)声明。属性提供了封装,无需样板代码。
基本属性声明
最简单的属性声明由类型和可选的初始化器组成。Kotlin 自动提供默认访问器。这是一个基本的使用属性的例子。
package com.zetcode class Person { var name: String = "John Doe" val age: Int = 30 } fun main() { val person = Person() println(person.name) // Output: John Doe person.name = "Jane Smith" // Setter called println(person.name) // Output: Jane Smith }
此示例显示了一个可变的 name
属性和只读的 age
属性。name
可以更改,而 age
则不能。Kotlin 自动生成默认的 getter 和 setter。
自定义 Getter 和 Setter
属性可以在属性声明后定义自定义访问器。get
和 set
块允许自定义逻辑。setter 参数通常命名为 value
。
package com.zetcode class Rectangle(val width: Int, val height: Int) { val area: Int get() = width * height var borderColor: String = "black" set(value) { if (value in listOf("black", "red", "blue")) { field = value } } } fun main() { val rect = Rectangle(10, 20) println(rect.area) // Output: 200 rect.borderColor = "red" println(rect.borderColor) // Output: red }
这里 area
是一个带有自定义 getter 的计算属性。borderColor
具有带有验证的 setter。field
标识符引用后备字段。无效的颜色被默默忽略。
后备字段
Kotlin 在需要时自动提供后备字段,通过 field
标识符访问。当自定义访问器引用它们时,后备字段存储属性值。它们仅在访问器中使用时才生成。
package com.zetcode class Counter { var count: Int = 0 set(value) { if (value >= 0) { field = value } } val isZero: Boolean get() = count == 0 } fun main() { val counter = Counter() counter.count = 5 println(counter.count) // Output: 5 counter.count = -3 // Ignored println(counter.count) // Output: 5 println(counter.isZero) // Output: false }
count
属性使用后备字段来存储其值。setter 验证输入,忽略负数。isZero
是一个没有后备字段的计算属性,因为它不存储状态。
延迟初始化属性
用 lateinit
标记的属性可以在声明后初始化。它们必须是 var
且不可为空。当依赖注入或测试设置初始化属性时很有用。
package com.zetcode class Service { lateinit var apiClient: ApiClient fun initialize(client: ApiClient) { apiClient = client } fun callService() { if (::apiClient.isInitialized) { apiClient.call() } } } class ApiClient { fun call() = println("API called") } fun main() { val service = Service() service.initialize(ApiClient()) service.callService() // Output: API called }
apiClient
在没有初始化器的情况下声明,但必须在使用前设置。isInitialized
检查可防止 UninitializedPropertyAccessException。这种模式在 Spring 等框架中很常见。
委托属性
Kotlin 使用 by
关键字支持属性委托。委托处理属性访问逻辑。常见的委托包括 lazy
、observable
和 vetoable
。
package com.zetcode import kotlin.properties.Delegates class User { val lazyValue: String by lazy { println("computed!") "Hello" } var name: String by Delegates.observable("<no name>") { prop, old, new -> println("$old -> $new") } } fun main() { val user = User() println(user.lazyValue) // Output: computed! then Hello println(user.lazyValue) // Output: Hello (cached) user.name = "John" // Output: <no name> -> John user.name = "Jane" // Output: John -> Jane }
lazyValue
仅在第一次访问时计算并缓存。name
通过 observable 委托更改时通知。委托封装了常见的属性模式,减少了样板代码。
属性可见性
属性可见性修饰符控制对属性及其访问器的访问。Getter 继承属性可见性,而 setter 可以具有单独的修饰符。这使得封装更加灵活。
package com.zetcode class BankAccount { var balance: Double = 0.0 private set fun deposit(amount: Double) { if (amount > 0) { balance += amount } } fun withdraw(amount: Double): Boolean { if (amount <= balance) { balance -= amount return true } return false } } fun main() { val account = BankAccount() account.deposit(100.0) println(account.balance) // Output: 100.0 // account.balance = 200.0 // Compile error }
balance
属性具有公共 getter 但私有 setter。更改必须通过受控方法 deposit
和 withdraw
进行。这确保了适当的验证和业务规则。
扩展属性
Kotlin 允许通过扩展向现有类添加属性。扩展属性没有后备字段。它们必须定义显式 getter(和 var
的 setter)。
package com.zetcode val String.hasDigits: Boolean get() = this.any { it.isDigit() } var StringBuilder.lastChar: Char get() = this[this.length - 1] set(value) { this.setCharAt(this.length - 1, value) } fun main() { val text = "Hello123" println(text.hasDigits) // Output: true val builder = StringBuilder("Kotlin") builder.lastChar = '!' println(builder) // Output: Kotli! }
hasDigits
是一个扩展属性,用于检查字符串中的数字。lastChar
用可变的最后一个字符访问权限扩展 StringBuilder。扩展属性增强了现有类型,无需继承。
属性的最佳实践
- 优先使用属性而不是 Java 风格的 get/set 方法: Kotlin 的属性更简洁、更符合习惯用法。
- 明智地使用自定义访问器: 将复杂的逻辑保留在方法中,而不是使属性访问器膨胀。
- 考虑不可变性: 对于初始化后不应更改的属性,请使用
val
。 - 在 setter 中进行验证: 使用属性 setter 进行简单的验证逻辑。
- 利用委托: 使用内置委托来处理常见的模式,如延迟初始化或可观察对象。
来源
本教程深入介绍了 Kotlin 属性,展示了声明、访问器、委托和扩展。属性提供了一种通过简洁的语法管理类状态的强大方法。正确使用属性可以编写更清晰、更易于维护的 Kotlin 代码。
作者
列出 所有 Kotlin 教程。