延迟初始化
Koltin中属性在声明的同时也要求要被初始化,否则会报错。例如以下代码:
private var name0: String // 报错 private var name1: String = "xiaoming" // 不报错 private var name2: String? = null // 不报错
可是有的时候,我并不想声明一个类型可空的对象,而且我也没办法在对象一声明的时候就为它初始化,那么这时就需要用到Kotlin提供的延迟初始化。
Kotlin中有两种延迟初始化的方式,分别是
lateinit var
和by lazy
。
lateinit var
private lateinit var name: String
lateinit var只能用来修饰类属性,不能用来修饰局部变量,并且只能用来修饰对象,不能用来修饰基本类型(因为基本类型的属性在类加载后的准备阶段都会被初始化为默认值)。
lateinit var的作用也比较简单,就是让编译期在检查时不要因为属性变量未被初始化而报错。
Kotlin相信当开发者显式使用lateinit var 关键字的时候,他一定也会在后面某个合理的时机将该属性对象初始化的(然而,谁知道呢,也许他用完才想起还没初始化,那么你就会遇到UninitializedPropertyAccessException)。
by lazy
by lazy本身是一种属性委托。属性委托的关键字是by
。by
关键字在kotlin中表达的委托的概念,by lazy只是会在使用到的时候进行初始化(类似懒汉式的单例),使用代理的方式调用get/set方法,所以var 不能声明by lazy修饰的属性。
by lazy 的写法如下:
// 用于属性延迟初始化 val name: Int by lazy { 1 } // 用于局部变量延迟初始化 public fun foo() { val bar by lazy { "hello" } println(bar) }
by lazy要求属性声明为val
,即不可变变量,在java中相当于被final
修饰。
这意味着该变量一旦初始化后就不允许再被修改值了(基本类型是值不能被修改,对象类型是引用不能被修改)。{}
内的操作就是返回唯一一次初始化的结果。
by lazy可以使用于类属性或者局部变量。
使用场景
虽然两者都可以推迟属性初始化的时间,但应用场景是略有不同的。
lateinit var只是让编译期忽略对属性未初始化的检查,后续在哪里以及何时初始化还需要开发者自己决定。
by lazy真正做到了声明的同时也指定了延迟初始化时的行为,在属性被第一次被使用的时候能自动初始化,但这些功能是要为此付出一丢丢代价的。