Kotlin Academy · 课时

lateinit 与延迟初始化

使用 lateinit 声明稍后赋值的属性,并使用 by lazy 延迟计算。

第 4 / 4 课13 个步骤

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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 主构造函数与属性参数
  2. init 代码块与初始化顺序
  3. 使用 field 自定义 Getter 与 Setter
  4. lateinit 与延迟初始化
← 返回 Kotlin Academy