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
相关推荐
赏金术士6 小时前
Compose 教学项目
android·kotlin·compose
晓梦林6 小时前
ximai靶场学习笔记
android·笔记·学习
kkeeper~7 小时前
0基础C语言积跬步之深入理解指针(5下)
c语言·开发语言
一直不明飞行7 小时前
Java的equals(),hashCode()应该在什么时候重写
java·开发语言·jvm
盲敲代码的阿豪7 小时前
Python 入门基础教程(爬虫前置版)
开发语言·爬虫·python
basketball6167 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
互联科技报8 小时前
2026超融合选型:Top5品牌与市场格局解读
开发语言·perl
weixin199701080168 小时前
[特殊字符] 智能数据采集:数字化转型的“数据石油勘探队”(附Python实战源码)
开发语言·python
想唱rap8 小时前
IO多路转接之poll
服务器·开发语言·数据库·c++
@杰克成9 小时前
Java学习30
java·开发语言·学习