Kotlin private 关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的访问修饰符控制类、对象和成员的可见性。private 关键字是最严格的修饰符。本教程将通过实际例子深入探讨 private 关键字。
基本定义
Kotlin 中的 private 关键字将可见性限制为声明作用域。私有成员只能在同一类或文件中访问。这通过隐藏实现细节来促进封装。
私有属性
私有属性只能在其声明的类中访问。这可以防止外部代码直接修改内部状态。
package com.zetcode
class BankAccount {
private var balance: Double = 0.0
fun deposit(amount: Double) {
if (amount > 0) {
balance += amount
}
}
fun getBalance(): Double = balance
}
fun main() {
val account = BankAccount()
account.deposit(100.0)
println(account.getBalance()) // Output: 100.0
// account.balance = 500.0 // Error: Cannot access 'balance'
}
在这里,balance 是私有的,只能通过 deposit 方法修改。禁止从类外部直接访问,确保对余额进行受控修改。
私有函数
私有函数是仅在其声明的类中可访问的辅助方法。它们有助于将复杂的操作分解为更小的步骤。
package com.zetcode
class Calculator {
fun add(a: Int, b: Int): Int {
validateInput(a, b)
return a + b
}
private fun validateInput(a: Int, b: Int) {
require(a >= 0 && b >= 0) {
"Inputs must be non-negative"
}
}
}
fun main() {
val calc = Calculator()
println(calc.add(5, 3)) // Output: 8
// calc.validateInput(2, 2) // Error: Cannot access 'validateInput'
}
validateInput 函数是私有的,由 add 方法内部使用。外部代码无法直接调用此验证函数,从而保持验证逻辑的封装性。
私有构造函数
私有构造函数可防止直接实例化类。这对于单例模式或工厂方法很有用。
package com.zetcode
class Database private constructor() {
companion object {
private var instance: Database? = null
fun getInstance(): Database {
if (instance == null) {
instance = Database()
}
return instance!!
}
}
fun query(sql: String) = println("Executing: $sql")
}
fun main() {
val db = Database.getInstance()
db.query("SELECT * FROM users")
// val db2 = Database() // Error: Cannot access ''
}
私有构造函数强制客户端使用 getInstance 获取一个 Database 对象。这确保只存在一个实例(单例模式)。实例变量也是私有的,以防止外部修改。
顶级声明中的私有
当用于顶级声明(在任何类之外)时,private 将可见性限制为当前文件。这对于文件特定的实用程序很有用。
package com.zetcode
private const val MAX_RETRIES = 3
private fun logError(message: String) {
println("ERROR: $message")
}
class NetworkClient {
fun fetchData() {
var attempts = 0
while (attempts < MAX_RETRIES) {
try {
// Network operation
return
} catch (e: Exception) {
logError(e.message ?: "Unknown error")
attempts++
}
}
}
}
// In another file:
// fun test() {
// println(MAX_RETRIES) // Error: Cannot access 'MAX_RETRIES'
// logError("Test") // Error: Cannot access 'logError'
// }
常量 MAX_RETRIES 和函数 logError 都对该文件是私有的。它们可以在文件中使用,但无法从其他文件访问,即使在同一包中也是如此。
私有 Setter
属性可以具有私有 Setter,同时保持 Getter 为公共。这允许对外部代码进行只读访问,同时允许内部修改。
package com.zetcode
class User(name: String) {
var name: String = name
private set
fun changeName(newName: String) {
if (newName.isNotBlank()) {
name = newName
}
}
}
fun main() {
val user = User("Alice")
println(user.name) // Output: Alice
user.changeName("Bob")
println(user.name) // Output: Bob
// user.name = "Charlie" // Error: Cannot assign to 'name'
}
name 属性具有公共 Getter,但具有私有 Setter。外部代码可以读取名称,但只能通过 changeName 方法修改它,该方法可以强制执行验证规则。
嵌套类中的私有
嵌套类中的私有成员的行为类似于常规类,可见性仅限于嵌套类作用域。
package com.zetcode
class Outer {
private val outerSecret = "Outer secret"
inner class Inner {
private val innerSecret = "Inner secret"
fun revealSecrets() {
println(outerSecret) // Can access outer's private members
println(innerSecret)
}
}
fun testInner() {
val inner = Inner()
inner.revealSecrets()
// println(inner.innerSecret) // Error: Cannot access 'innerSecret'
}
}
fun main() {
val outer = Outer()
outer.testInner()
// println(outer.outerSecret) // Error: Cannot access 'outerSecret'
}
内部类可以访问其外部类的私有成员,但内部类的私有成员无法被外部类访问。两个类的私有成员都无法从 Outer 类外部访问。
接口中的私有
从 Kotlin 1.4 开始,Kotlin 接口可以具有私有函数。这些函数只能在接口及其实现中使用。
package com.zetcode
interface Logger {
fun log(message: String)
private fun formatMessage(message: String): String {
return "[${System.currentTimeMillis()}] $message"
}
fun logWithTimestamp(message: String) {
log(formatMessage(message))
}
}
class ConsoleLogger : Logger {
override fun log(message: String) {
println(message)
}
}
fun main() {
val logger = ConsoleLogger()
logger.logWithTimestamp("Hello, Kotlin!")
// logger.formatMessage("Test") // Error: Cannot access 'formatMessage'
}
formatMessage 函数对 Logger 接口是私有的。它可以被其他接口成员(如 logWithTimestamp)使用,但无法被实现类或外部代码访问。
private 关键字的最佳实践
- 默认为 private: 默认情况下将成员设为私有,并且仅公开必要的内容。
- 封装状态: 使用具有受控访问方法 的私有属性来维护对象完整性。
- 隐藏实现: 保持辅助方法私有,以简化您的公共 API。
- 考虑可见性: 选择仍然允许必要访问的最严格的可见性。
- 记录公共 API: 重点关注公共成员的文档,因为私有成员是实现细节。
来源
本教程深入介绍了 Kotlin 的 private 关键字,展示了各种应用,包括属性、函数、构造函数和嵌套类。正确使用私有可见性可以促进封装,并通过隐藏实现细节来创建更易于维护的代码。
作者
列出 所有 Kotlin 教程。