Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?

简介: **Kotlin中的`by lazy`和`lateinit`都是延迟初始化技术。`by lazy`用于只读属性,线程安全,首次访问时初始化;`lateinit`用于可变属性,需手动初始化,非线程安全。`by lazy`支持线程安全模式选择,而`lateinit`适用于构造函数后初始化。选择依赖于属性特性和使用场景。**

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点

在Kotlin中,by lazylateinit 都是用于延迟初始化的手段,但它们各自有不同的用法和特点。下面详细讨论它们的作用和区别。

1. by lazy

作用

by lazy 是一种委托属性,用于延迟初始化一个只读属性。属性在第一次访问时才会被初始化,并且初始化操作只会执行一次。

用法

语法:val property: Type by lazy { initializer }

lazy 的默认线程安全模式是 LazyThreadSafetyMode.SYNCHRONIZED,它确保多线程环境下属性只会被初始化一次。

示例

val myValue: String by lazy {
    println("Computed only once")
    "Hello, World!"
}

// 第一次访问 myValue,会触发初始化代码块执行
println(myValue) // 输出: "Computed only once" 和 "Hello, World!"
// 之后的访问不会重复执行初始化代码块
println(myValue) // 输出: "Hello, World!"

惰性线程安全模式

  • LazyThreadSafetyMode.SYNCHRONIZED:默认值,确保多线程环境下属性只能被初始化一次。
  • LazyThreadSafetyMode.PUBLICATION:允许多个线程在同一时间初始化,但只使用第一个完成的结果。
  • LazyThreadSafetyMode.NONE:不进行任何同步,适用于单线程环境。

示例

val valueSynchronized: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
    "Synchronized"
}

val valuePublication: String by lazy(LazyThreadSafetyMode.PUBLICATION) {
    "Publication"
}

val valueNone: String by lazy(LazyThreadSafetyMode.NONE) {
    "None"
}

2. lateinit

作用

lateinit 是一种延迟初始化的关键字,用于延迟初始化一个 var 可变属性。属性类型必须是非空的且不能是原始类型(如 Int, Double)。

用法

语法:lateinit var property: Type

lateinit 属性不能有自定义的 getter 和 setter,必须在使用之前显式初始化,否则会抛出 UninitializedPropertyAccessException

示例

lateinit var myValue: String

fun initialize() {
    myValue = "Hello, World!"
}

// 使用之前必须显式初始化
initialize()
println(myValue) // 输出: "Hello, World!"

检查初始化

  • 可以使用 ::property.isInitialized 语法来检查属性是否已经初始化。
    if (::myValue.isInitialized) {
      println(myValue)
    } else {
      println("myValue is not initialized")
    }
    

3. 两者对比

特性 by lazy lateinit
适用类型 val(只读属性) var(可变属性)
初始化时机 第一次访问时 必须手动初始化
线程安全 默认线程安全(可选择不同的线程安全模式) 非线程安全
Nullability 支持不可空类型 支持不可空类型(不能用于原始类型)
属性检查 不需要显式检查 可以通过 ::property.isInitialized 检查
自定义 getter/setter 不支持 不支持
使用场景 用于只读且惰性初始化的属性 用于需要在构造函数之外初始化的可变属性

示例场景

by lazy 适用场景:

  • 需要惰性初始化不可变的属性。
  • 需要线程安全的初始化或者只在单线程中操作。

    lateinit 适用场景:

    • 需要在构造方法之后初始化的可变属性。
  • 需要在某个特定操作时才对属性进行赋值。

总结来说,选择使用 by lazy 还是 lateinit 要依据属性的特性和具体的使用场景。by lazy 更适合不可变的延迟初始化场合,而 lateinit 则适用于在构造方法之后需要手动初始化的可变属性。


欢迎关注我的公众号AntDream查看更多精彩文章!

目录
相关文章
|
4天前
|
SQL 数据库
SQL面试50题------(初始化工作、建立表格)
这篇文章提供了SQL面试中可能会遇到的50道题目的建表和初始化数据的SQL脚本,包括学生、教师、课程和成绩表的创建及数据插入示例。
SQL面试50题------(初始化工作、建立表格)
|
18天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android 消息处理机制估计都被写烂了,但是依然还是要写一下,因为Android应用程序是通过消息来驱动的,Android某种意义上也可以说成是一个以消息驱动的系统,UI、事件、生命周期都和消息处理机制息息相关,并且消息处理机制在整个Android知识体系中也是尤其重要,在太多的源码分析的文章讲得比较繁琐,很多人对整个消息处理机制依然是懵懵懂懂,这篇文章通过一些问答的模式结合Android主线程(UI线程)的工作原理来讲解,源码注释很全,还有结合流程图,如果你对Android 消息处理机制还不是很理解,我相信只要你静下心来耐心的看,肯定会有不少的收获的。
58 3
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
18天前
|
Android开发
Android面试高频知识点(1) 图解 Android 事件分发机制
在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少。废话不多说,总结一句:事件分发机制很重要。
63 9
|
18天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
View的绘制和事件处理是两个重要的主题,上一篇《图解 Android事件分发机制》已经把事件的分发机制讲得比较详细了,这一篇是针对View的绘制,View的绘制如果你有所了解,基本分为measure、layout、draw 过程,其中比较难理解就是measure过程,所以本篇文章大幅笔地分析measure过程,相对讲得比较详细,文章也比较长,如果你对View的绘制还不是很懂,对measure过程掌握得不是很深刻,那么耐心点,看完这篇文章,相信你会有所收获的。
39 2
|
19天前
|
监控 Android开发 开发者
Android经典面试题之实战经验分享:如何简单实现App的前后台监听判断
本文介绍在Android中判断应用前后台状态的两种方法:`ActivityLifecycleCallbacks`和`ProcessLifecycleOwner`。前者提供精细控制,适用于需针对每个Activity处理的场景;后者简化前后台检测,适用于多数应用。两者各有优劣:`ActivityLifecycleCallbacks`更精确但复杂度高;`ProcessLifecycleOwner`更简便但可能在极端场景下略有差异。根据应用需求选择合适方法。
18 2
|
25天前
|
Android开发 开发者
Android经典面试题之SurfaceView和TextureView有什么区别?
分享了`SurfaceView`和`TextureView`在Android中的角色。`SurfaceView`适于视频/游戏,独立窗口低延迟,但变换受限;`TextureView`支持复杂变换,视图层级中渲染,适合动画/视频特效,但性能略低。两者在性能、变换、使用和层级上有差异,开发者需按需选择。
14 1
|
11天前
|
Java 开发工具 Android开发
Android经典面试题之开发中常见的内存泄漏,以及如何避免和防范
本文介绍Android开发中内存泄漏的概念及其危害,并列举了四种常见泄漏原因:静态变量持有Context、非静态内部类、资源未释放及监听器未注销。提供了具体代码示例和防范措施,如使用ApplicationContext、弱引用、适时释放资源及利用工具检测泄漏。通过遵循这些建议,开发者可以有效提高应用稳定性和性能。
21 0
|
26天前
|
消息中间件 调度 Android开发
Android经典面试题之View的post方法和Handler的post方法有什么区别?
本文对比了Android开发中`View.post`与`Handler.post`的使用。`View.post`将任务加入视图关联的消息队列,在视图布局后执行,适合视图操作。`Handler.post`更通用,可调度至特定Handler的线程,不仅限于视图任务。选择方法取决于具体需求和上下文。
26 0
|
3天前
|
存储 缓存 网络协议
复盘女朋友面试4个月的Java基础题
这篇文章是关于Java基础面试题的复盘,涵盖了HashMap原理、对象序列化作用等高频面试问题,并强调了Java基础知识的重要性。
复盘女朋友面试4个月的Java基础题
|
5天前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)