这是正确的 "lateinit var text : String?" 吗?

Is this correct "lateinit var text : String?"?

我想知道这行代码是否正确,我的老师告诉我它是正确的,但我不同意,因为 "lateinit" 不能与可能为 null 或不为 null 的变量一起使用。 线路代码:

    lateinit var text : String?

代码:

    val cadena = null
    lateinit var text : String?
    text = null
    text = cadena ?: "Hola"
    text?.let { println(text) }

你是对的,你的老师是错的。证明:lateinit var text : String? 导致 Kotlin 1.3.50 编译错误:

'lateinit' modifier is not allowed on properties of nullable types

我无法理解任何老师怎么可能声称这样的代码是正确的...

我想深入了解 Kotlin 中的 lateinit 属性。

'lateinit' 修饰符不允许用于可空类型 的属性 - 这可以在 Kotlin 文档中找到。这种改性剂适用于特殊的结构。它适用于 将在对象创建 之后的某个时间初始化的字段。例如,通过 DI 框架或模拟框架。

但是,那个字段下面是什么?如果我们检查它,我们会简单地发现在初始化之前 属性 有 null 值。不多也不少,就是 null。但是,如果我们想在初始化 UninitializedPropertyAccessException 被抛出之前访问 属性。

在 Kotlin 1.3 中 lateinit 属性有了新的 属性 - isInitialized(要使用它:::lateinitiProperty.isInitilized)。因此,在我们访问 属性 之前,我们能够检查该字段下是否是 null 或其他内容,而不会抛出异常。

但是,lateinit 意味着对象稍后将被初始化为非空 属性。并且程序员保证这个值在初始化后不为空。如果可以,为什么不使用 nullable 类型?

是否有办法取消初始化 lateinit 属性?是的。通过反射,我们可以再次将该值设置为空(JVM 不是空安全的)。并且访问该字段不会以 NPE 执行结束,而是以 UninitializedPropertyAccessException 结束。对于引用 null 的字段,.isInitialized 将 return false。

它是如何工作的?

class MyClass {
    lateinit var lateinitObject: Any

    fun test() {
        println("Is initialized: ${::lateinitObject.isInitialized}") // false
        lateinitObject = Unit
        println("Is initialized: ${::lateinitObject.isInitialized}") // true

        resetField(this, "lateinitObject")
        println("Is initialized: ${::lateinitObject.isInitialized}") // false again

        lateinitObject // this will throw UninitializedPropertyAccessException
    }
}

fun resetField(target: Any, fieldName: String) {
    val field = target.javaClass.getDeclaredField(fieldName)

    with (field) {
        isAccessible = true
        set(target, null)
    }
}

Ofc,以这种方式使用 lateinit 可能不是您想要的,并且将其视为关于 JVM 中 lateinit 设计的古玩。

而且由于你的老师 - 他是不对的。即使 lateinit 可能引用 null(实际上确实如此),您也不能将其声明为可空类型。如果需要,则不需要 lateinit 修饰符。