Kotlin internal 关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的可见性修饰符控制声明的范围。internal
关键字提供模块级别的可见性。本教程通过实际示例深入探讨了 internal
修饰符。
基本定义
Kotlin 中的 internal
关键字使声明在同一模块内可见。 模块是一组一起编译的 Kotlin 文件。这在大型项目的不同部分之间提供了封装。
Internal 类
Internal 类可以在同一模块内的任何地方访问,但不能在模块外访问。 这对于不应公开的实现细节很有用。
package com.zetcode internal class DatabaseHelper { fun connect() = println("Connecting to database") } fun main() { val db = DatabaseHelper() db.connect() // Works within same module }
这里我们定义一个 internal 的 DatabaseHelper
类。 它可以在同一模块中使用,但如果导入到另一个模块中,将无法访问。
Internal 函数
函数可以标记为 internal,以将其可见性限制为当前模块。 这有助于隐藏实现细节,同时在整个模块中保持可用性。
package com.zetcode internal fun calculateDiscount(price: Double): Double { return price * 0.9 // 10% discount } fun main() { val total = calculateDiscount(100.0) println("Discounted price: $total") // Output: 90.0 }
calculateDiscount
函数是 internal 的,因此可以在模块中的任何地方调用它,但不能从其他模块调用。 这保护了业务逻辑。
Internal 属性
属性也可以标记为 internal。 这控制了对类字段的访问,同时使其在整个模块中可用于内部使用。
package com.zetcode class ShoppingCart { internal var discountApplied = false fun applyDiscount() { discountApplied = true } } fun main() { val cart = ShoppingCart() cart.applyDiscount() println("Discount applied: ${cart.discountApplied}") // Output: true }
discountApplied
属性是 internal 的,因此可以在模块内访问,但不能从外部访问。 这保持了封装性。
Internal 接口
接口可以标记为 internal,以将其使用限制为当前模块。 这对于不应在模块外实现的契约很有用。
package com.zetcode internal interface Logger { fun log(message: String) } class ConsoleLogger : Logger { override fun log(message: String) { println("LOG: $message") } } fun main() { val logger: Logger = ConsoleLogger() logger.log("Test message") // Output: LOG: Test message }
Logger
接口是 internal 的,因此只能在同一模块内实现。 这控制了如何扩展日志记录系统。
在不同包中的 Internal
Internal 可见性在同一模块内的不同包之间工作。 这允许组织,同时保持对 internal 声明的访问。
// File 1: com/zetcode/auth/Authenticator.kt package com.zetcode.auth internal class Authenticator { fun authenticate() = println("Authenticating...") } // File 2: com/zetcode/main.kt package com.zetcode import com.zetcode.auth.Authenticator fun main() { val auth = Authenticator() // Accessible in same module auth.authenticate() }
Authenticator
类是 internal 的,但可以从同一模块中的另一个包访问。 这演示了模块范围的可见性。
Internal 构造函数
构造函数可以标记为 internal,以控制如何在模块边界之间实例化类,同时允许在模块内构造。
package com.zetcode class ApiClient internal constructor(val apiKey: String) { fun makeRequest() = println("Making request with key: $apiKey") } fun createClient(key: String): ApiClient { return ApiClient(key) // Can call internal constructor } fun main() { val client = createClient("secret123") client.makeRequest() // Output: Making request with key: secret123 }
ApiClient
有一个 internal 构造函数,因此只能在模块内创建。 createClient
函数提供了受控的实例化。
Internal 和继承
Internal 可见性会影响继承。 internal 类或成员可以被同一模块内的子类覆盖,但不能从外部覆盖。
package com.zetcode open internal class BaseService { internal open fun start() = println("Base service starting") } class CustomService : BaseService() { override fun start() { println("Custom service starting") super.start() } } fun main() { val service = CustomService() service.start() // Output: // Custom service starting // Base service starting }
internal 的 BaseService
可以在同一模块内扩展。 start
方法可以被子类中的 internal 或更可见的成员覆盖。
Internal 可见性的最佳实践
- 用于模块 API:将实现细节标记为 internal,同时公开公共 API。
- 组织大型项目:使用 internal 在模块内共享代码,同时将其隐藏在其他模块中。
- 与其他修饰符结合使用:Internal 可以与 protected 或 private 结合使用,以实现更精确的控制。
- 记录 internal API: 清楚地记录 internal 声明的预期用法,供模块维护人员参考。
- 考虑替代可见性:对于真正私有的代码,使用 private 而不是 internal。
来源
本教程深入探讨了 Kotlin 的 internal
关键字,展示了它如何提供模块级别的可见性控制。 我们探讨了各种场景,包括类、函数、属性和继承。 正确使用 internal 可见性有助于创建封装良好、可维护的模块。
作者
列出 所有 Kotlin 教程。