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

时间:2019-10-21 04:39:56

标签: kotlin syntax kotlin-lateinit

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

    lateinit var text : String?

代码:

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

2 个答案:

答案 0 :(得分:3)

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

  可空类型的属性上不允许使用

'lateinit'修饰符

任何一位老师怎么可能声称这样的代码是正确的……

答案 1 :(得分:1)

我想对Kotlin的Lateinit属性进行一些深入的研究。

在可空类型的属性上不允许使用

'lateinit'修饰符-可以在Kotlin文档中找到。这种修饰剂用于特殊类型的结构。对于在创建对象后会初始化的字段。例如,通过DI框架或模拟框架。

但是,该字段下的内容是什么?如果要检查它,我们将简单地发现在初始化属性具有null值之前。仅此null,仅此而已。但是,如果我们想在初始化UninitializedPropertyAccessException引发之前访问该属性。

在Kotlin 1.3中,lateinit属性获得了新属性-isInitialized(要使用:::lateinitiProperty.isInitilized)。因此,在访问该属性之前,我们可以检查该字段下的内容是否为null或其他内容,而不会引发异常。

但是,lateinit表示对象将在以后初始化为非null属性。并且程序员保证初始化后该值不为null。如果可能的话,为什么不使用nullable类型呢?

是否有一种方法可以取消初始化Lateinit属性?是的。通过反射,我们可以将该值再次设置为null(JVM不是null安全的)。并且访问该字段将不会以NPE执行,而是会以UninitializedPropertyAccessException完成。对于指向null的字段,.isInitialized将返回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(并且实际上引用了),也不能将其声明为可为null的类型。如果需要,则不需要lateinit修饰符。