Kotlin -> lateinit 和 lazy 详解

lateinitlazy 详解

核心区别

特性 lateinit lazy
类型 可变属性修饰符 var 不可变属性委托 val
初始化时机 手动显式初始化,随时可变 首次访问时自动初始化,之后不可变
空安全 非空类型,但初始值可缺失 非空类型,保证有值
适用类型 不能用于基本类型(Int, Boolean等) 可用于任何类型
线程安全 不保证线程安全 默认线程安全SYNCHRONIZED模式
检查机制 使用前需确保已初始化,否则抛异常 自动处理初始化,不会抛出未初始化异常

lateinit 核心用法

kotlin 复制代码
// 声明
class User {
    lateinit var name: String
    
    fun initialize() {
        name = "John" // 手动初始化
    }
    
    fun greet() {
        if (::name.isInitialized) { // 检查是否已初始化
            println("Hello, $name")
        }
    }
}

最佳使用场景:

  • 依赖注入
  • Activity/Fragment中的视图绑定
  • 单元测试的setUp方法中
  • 需要推迟初始化但之后可能需要修改的属性

lazy 核心用法

kotlin 复制代码
// 基本用法
class User {
    val name: String by lazy { 
        println("Computing name...")
        "John" // 计算并返回初始值
    }
}

// 指定线程安全模式
val expensiveData: List<Data> by lazy(LazyThreadSafetyMode.PUBLICATION) {
    loadDataFromDatabase()
}

线程安全模式:

  • SYNCHRONIZED:默认模式,线程安全,只执行一次初始化
  • PUBLICATION:多线程可能执行多次,但只有第一个结果被使用
  • NONE:不保证线程安全,适用于单线程环境,性能最好

最佳使用场景:

  • 计算开销大的属性
  • 需要根据条件计算的只读属性
  • 单例模式实现
  • 配置项和缓存数据

核心实现原理

lateinit

  • 在字节码级别,不为属性分配默认值
  • 访问前不进行空检查
  • 使用前若未初始化,抛出UninitializedPropertyAccessException

lazy

  • 内部使用SynchronizedLazyImpl等实现类
  • 持有一个初始化器函数和一个存储结果的AtomicReference
  • 首次访问时执行初始化器并缓存结果

如何选择

  • 如果属性需要在初始化后修改,使用lateinit var
  • 如果属性是只读的且可以延迟计算,使用lazy val
  • 如果处理基本类型,只能使用lazy
  • 如果在多线程环境中,优先考虑lazy
相关推荐
Humbunklung4 分钟前
Rust方法语法:赋予结构体行为的力量
开发语言·后端·rust
萧曵 丶10 分钟前
Rust 内存结构:深入解析
开发语言·后端·rust
算法练习生16 分钟前
Qt核心类QWidget及其派生类详解
开发语言·c++·qt
移动开发者1号23 分钟前
Kotlin协程超时控制:深入理解withTimeout与withTimeoutOrNull
android·kotlin
1024小神32 分钟前
tauri项目在windows上的c盘没有权限写入文件
c语言·开发语言·windows
程序员JerrySUN38 分钟前
RK3588 Android SDK 实战全解析 —— 架构、原理与开发关键点
android·架构
老虎062740 分钟前
数据结构(Java)--位运算
java·开发语言·数据结构
yanjiaweiya41 分钟前
云原生-集群管理续
java·开发语言·云原生
Swift社区41 分钟前
Swift 解 LeetCode 320:一行单词有多少种缩写可能?用回溯找全解
开发语言·leetcode·swift
写不出来就跑路1 小时前
暑期实习感悟与经验分享:从校园到职场的成长之路
java·开发语言·经验分享·spring boot