我需要知道这行代码是否正确,我的老师告诉我它是正确的,但我不同意,因为“lateinit”不能与可以为空或不为空的变量一起使用。线路代码:
lateinit var text : String?
代码:
val cadena = null
lateinit var text : String?
text = null
text = cadena ?: "Hola"
text?.let { println(text) }
我需要知道这行代码是否正确,我的老师告诉我它是正确的,但我不同意,因为“lateinit”不能与可以为空或不为空的变量一起使用。线路代码:
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”修饰符
任何老师怎么可能声称这样的代码是正确的,这超出了我的范围......
我想深入探讨 Kotlin 中的 lateinit 属性。
可空类型的属性不允许使用“lateinit”修饰符- 这可以在 Kotlin 文档中找到。这种修饰符适用于特殊类型的结构。它用于在对象创建后将被初始化的字段。例如,通过 DI 框架或模拟框架。
但是,那个领域是什么?如果我们检查它,我们会简单地发现在初始化之前的属性是有null
值的。仅此而已,仅此而已null
。但是,如果我们想在UninitializedPropertyAccessException
引发初始化之前访问该属性。
在 Kotlin 1.3中lateinit
,属性获得了新属性 - isInitialized
(使用它:) ::lateinitiProperty.isInitilized
。因此,在我们访问该属性之前,我们能够检查该字段下是否是null
或其他内容,而不会引发异常。
但是,lateinit
意味着该对象稍后将被初始化为非空属性。并且程序员保证初始化后这个值不为空。如果可以,为什么不使用nullable
类型?
如果有办法取消初始化 lateinit 属性?是的。通过反射,我们可以再次将该值设置为 null(JVM 不是 null 安全的)。并且访问该字段不会以NPE
execption 结束,而是以UninitializedPropertyAccessException
. 并且.isInitialized
将为引用 null 的字段返回 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 可能不是您想要的,并且将其视为有关lateinit
JVM 设计的古玩。
由于你的老师 - 他是不对的。即使lateinit
可以引用 null(实际上确实如此),您也不能将其声明为可为 null 的类型。如果需要,则不需要lateinit
修饰符。