美文网首页
Kotlin-延迟初始化

Kotlin-延迟初始化

作者: 有腹肌的豌豆Z | 来源:发表于2020-12-30 21:31 被阅读0次

    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<Button>(R.id.bt)
        }
        
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            bt.setOnClickListener {
                Toast.makeText(baseContext, "click", Toast.LENGTH_SHORT).show()
            }
        }
    }
    

    lazy 延迟模式

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

    public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
        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 <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
    

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

    class Manager {
    
        init {
            Log.e("zhaoyanjun:inin", "初始化")
        }
    
        companion object {
            val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
                Manager()
            }
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Kotlin-延迟初始化

          本文链接:https://www.haomeiwen.com/subject/kbqkoktx.html