Kotlin-延迟初始化

Koltin中属性在声明的同时也要求要被初始化,否则会报错。例如以下代码:

private var name0: String //报错
private var name1: String = "xiaoming" //不报错
private var name2: String? = null //不报错

可是有的时候,我并不想声明一个类型可空的对象,而且我也没办法在对象一声明的时候就为它初始化,那么这时就需要用到Kotlin提供的延迟初始化。Kotlin中有两种延迟初始化的方式。一种是 lateinit var,一种是by lazy


lateinit 延迟初始化

private lateinit var name: String
  • lateinit var只能用来修饰类属性,不能用来修饰局部变量,并且只能用来修饰对象,不能用来修饰基本类型(因为基本类型的属性在类加载后的准备阶段都会被初始化为默认值)。
  • lateinit var的作用也比较简单,就是让编译期在检查时不要因为属性变量未被初始化而报错。假的延迟,后面忘记了 那就 GG了
  • Kotlin相信当开发者显式使用lateinit var关键字的时候,他一定也会在后面某个合理的时机将该属性对象初始化的.
lateinit在Android中使用
private lateinit var s: String
private val ss:String by lazy { "132" }

fun main() {
    print("懒加载 ss = $ss")
    try {
        print("没有初始化 是s =  $s  \n")   // 必须要初始化之后才能使用
    }catch (e:Exception){
        e.printStackTrace()
    }
    s = "123456"
    print("初始化之后的  s =  $s")
}
class MainActivity : AppCompatActivity() {

    private lateinit var bt: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        bt = findViewById(R.id.bt)
        bt.setOnClickListener {
            Toast.makeText(baseContext, "click", Toast.LENGTH_SHORT).show()
        }
    }
}

lazy 延迟初始化

by lazy本身是一种属性委托。属性委托的关键字是byby lazy的写法如下:

//用于属性延迟初始化
val name: Int by lazy { 1 }
 
//用于局部变量延迟初始化
public fun foo() {
    val bar by lazy { "hello" }
    println(bar)
}

  • by lazy要求属性声明为val,即不可变变量,在java中相当于被final修饰。这意味着该变量一旦初始化后就不允许再被修改值了(基本类型是值不能被修改,对象类型是引用不能被修改)。{}内的操作就是返回唯一一次初始化的结果。
  • by lazy可以使用于类属性或者局部变量。

在 Android 中使用

class MainActivity : AppCompatActivity() {

   private val bt by lazy {
        findViewById

lazy 延迟模式

在使用 lazy 延迟初始化的时候,Kotlin提供了3中模式,源码如下:

public actual fun  lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy =
    when (mode) {
        LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
        LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
        LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
    }

private val sss:String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { "最后一个函数 可以放在外面 " }

  • 模式1: LazyThreadSafetyMode.SYNCHRONIZED
    线程安全模式,Initializer函数只能被调用一次,返回的对象只有一个
  • 模式2:LazyThreadSafetyMode.PUBLICATION
    在对未初始化的[Lazy]实例值进行并发访问时,可以多次调用Initializer函数,但只有第一个返回值将用作[Lazy]实例的值。
  • 模式3:LazyThreadSafetyMode.NONE
    没有锁用于同步对[Lazy]实例值的访问; 如果从多个线程访问实例,可能会有多个实例。除非保证[Lazy]实例永远不会从多个线程初始化,否则不应使用此模式。

当我们模式都不用的情况下,默认使用 LazyThreadSafetyMode.SYNCHRONIZED 线程安全模式。源码如下:

public actual fun  lazy(initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer)

几个例子,使用延迟模式创建一个单例

class Manager {

    init {
        Log.e("zhaoyanjun:inin", "初始化")
    }

    companion object {
        val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            Manager()
        }
    }
}

你可能感兴趣的:(Kotlin-延迟初始化)