I would like to add a little deep dive into lateinit properties in Kotlin.
'lateinit' modifier is not allowed on properties of nullable type - this can be found in Kotlin documentation. This kind of modifier is for special kind of constructions. It's for fields that will be initialized somewhen after object creation. For example, via DI framework or mocking framework.
But, what is under that field? If we would check it, we will simply find that before initialization property has null
value. Nothing more, nothing less, just null
. But, if we would like to access that property before initialization UninitializedPropertyAccessException
is thrown.
In Kotlin 1.3 lateinit
properties got new property - isInitialized
(to use it: ::lateinitiProperty.isInitilized
). So, before we access that property we are able to check if under that field is null
or something else, without throwing exception.
But, lateinit
means that object will be initialized later as not null property. And a programmer guarantee that this value is not null after intialization. If it could be, why just not use nullable
type?
If there is a way to uninialize lateinit property? Yes, it is. Via reflection we can set that value to null again (JVM is not null-safe). And accessing that field will not finish with NPE
execption, but with UninitializedPropertyAccessException
. And .isInitialized
will return false for field that refers to null.
And how does it work?
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, using lateinit that way is probably not what you want, and treat is as a curio about lateinit
design in JVM.
And due to your teacher - he wasn't right. Even if lateinit
may refer to null (and it does actually), you cannot declare it as a nullable type. If you need to, you don't need lateinit
modifier.