这是正确的 "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
修饰符。
我想知道这行代码是否正确,我的老师告诉我它是正确的,但我不同意,因为 "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
修饰符。