lateinit 与延迟初始化
使用 lateinit 声明稍后赋值的属性,并使用 by lazy 延迟计算。
lateinit 与延迟初始化 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
延迟设置的两种工具
有时您无法在构造时初始化属性。Kotlin 提供了 lateinit(用于稍后赋值的 var)和 by lazy(用于在首次访问时计算的 val)。
lateinit 基础
lateinit var 会延迟初始化。该变量必须是非空、非基本类型的 var。在赋值前访问它会抛出 UninitializedPropertyAccessException。
class Service {
lateinit var name: String
fun init(value: String) { name = value }
}
fun main() {
val s = Service()
s.init("MyService")
println(s.name)
}为什么使用 lateinit?
在依赖注入、测试夹具或由框架管理的生命周期(例如 Android 视图、Spring Bean)中,如果初始化发生在构造函数之外,请使用 lateinit。
class Repository {
lateinit var db: String // assigned later by DI framework
fun query() = "querying $db"
}
fun main() {
val r = Repository()
r.db = "postgres://localhost"
println(r.query())
}isInitialized 检查
您可以使用 ::propName.isInitialized 检查 lateinit 属性是否已赋值。
class Foo {
lateinit var bar: String
fun status() = if (::bar.isInitialized) "set to $bar" else "unset"
}
fun main() {
val f = Foo()
println(f.status()) // unset
f.bar = "hi"
println(f.status())
}lateinit 的限制
不能将 lateinit 用于基本类型(Int、Boolean 等)、可空类型或 val。编译器会强制执行这些规则。
// VALID:
lateinit var name: String
// INVALID:
// lateinit var count: Int // primitives not allowed
// lateinit val constant: String // val not allowed
// lateinit var maybe: String? // nullable not allowed
fun main() { name = "ok"; println(name) }by lazy 基础
by lazy 会将 val 的初始化延迟到首次访问时。Lambda 只运行一次,结果会被缓存。
val expensive: String by lazy {
println("Computing...")
"result"
}
fun main() {
println(expensive) // Computing... then result
println(expensive) // result (cached)
}为什么使用 by lazy?
当初始化成本较高且可能不需要执行时,请使用 by lazy(将结果缓存以便稍后使用);如果初始化依赖于已经构造完成的其他属性,也可以使用它。
class Config {
val parsed: Map<String, String> by lazy {
println("parsing config...")
mapOf("host" to "localhost", "port" to "8080")
}
}
fun main() {
val c = Config()
println("config object created — not parsed yet")
println(c.parsed["host"]) // now parses
println(c.parsed["port"]) // cached
}lazy 的线程安全模式
默认情况下,by lazy 使用 LazyThreadSafetyMode.SYNCHRONIZED。并发初始化可以接受时使用 PUBLICATION;单线程场景追求性能时使用 NONE。
val safe: String by lazy { "thread-safe" }
val fast: String by lazy(LazyThreadSafetyMode.NONE) { "fast, single-thread" }
fun main() {
println(safe)
println(fast)
}lateinit 与 lazy
lateinit:var,由外部赋值。by lazy:val,由属性自身在首次访问时计算。
class Demo {
lateinit var injected: String // assigned by caller
val computed: String by lazy { "computed once" }
}
fun main() {
val d = Demo()
d.injected = "from outside"
println(d.injected)
println(d.computed)
}lazy 读取其他属性
延迟属性可以读取其他属性(这些属性已先完成初始化)并将它们组合起来。
class User(val first: String, val last: String) {
val fullName: String by lazy { "$first $last" }
}
fun main() {
val u = User("Ada", "Lovelace")
println(u.fullName)
}实用模式
在同一个类中结合使用 lateinit 进行 DI,并使用 by lazy 保存派生状态。
class App {
lateinit var config: Map<String, String>
val host: String by lazy { config["host"] ?: "localhost" }
}
fun main() {
val app = App()
app.config = mapOf("host" to "api.example.com")
println(app.host) // api.example.com
}快速检查
哪个关键字会将 val 属性的初始化延迟到首次访问时?
回顾
对于由框架或 DI 在稍后赋值的非空可变属性,请使用 lateinit var。对于应在首次访问时计算一次的只读值,请使用 val by lazy。使用 ::prop.isInitialized 检查状态。
用 AI 导师学习 Kotlin — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 51
- 课程
- 203
常见问题解答
「lateinit 与延迟初始化」课时是免费的吗?
是的 — 「lateinit 与延迟初始化」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「lateinit 与延迟初始化」这节课中我会学到什么?
使用 lateinit 声明稍后赋值的属性,并使用 by lazy 延迟计算。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「lateinit 与延迟初始化」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 主构造函数与属性参数
- init 代码块与初始化顺序
- 使用 field 自定义 Getter 与 Setter
- lateinit 与延迟初始化