我需要知道此行代码是否正确,我的老师告诉我这是正确的,但是我不同意“因为“ lateinit”不能与可能为null的变量一起使用。 线路代码:
lateinit var text : String?
代码:
val cadena = null
lateinit var text : String?
text = null
text = cadena ?: "Hola"
text?.let { println(text) }
答案 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
修饰符。