如何安全地解决这个空初始化器检查?

我正在写一个测试用例,我需要一些私有属性。 由于这些私人数据是从私人方法生成的,我决定在计算完成后使用反射来检索它们。 后来我想起了委托的财产,并决定写一个总代表。 这是我到目前为止的代码:

fun <T> reflect(instance: Any, initOnce: Boolean = true) = ReflectBackedProperty<T>(initOnce, instance) class ReflectBackedProperty<T>(val initOnce: Boolean, val instance: Any): ReadOnlyProperty<Any, T> { var initialized = false lateinit var cache: T // <--- (a) override opertaor fun getValue(thisRef: Any, property: KProperty<*>): Any? { @Suppress("UNCHECKED_CAST") if (!initialized || !initOnce) { cache = instance.javaClass.getDeclaredField(property.name).get(instance) as T initialized = true } return cache } } 

如您所见,属性cachegetValue调用初始化,并且如果设置了initOnce ,则后续调用将使用该缓存而不是保持调用昂贵的反射。

非常不幸的是,在(a)编译器抱怨,因为T可能是一个可以为空的类型,晚期的init机制将被打破,但是如果我初始化它为null ,它仍然抱怨,因为T可能是一个非null类型,安全被打破。

目前,我通过使用返回null的Java函数的返回值来初始化它。 我检查了生成的字节码,发现kotlin编译器没有对它进行空的检查,所以现在可以工作,但是我担心未来的kotlin版本会有这样的检查并且毁掉这个技巧。 我应该如何克服这一点?


现在我正在使用这个,下面的代码被释放到公共领域。 如果你喜欢,可以提到这个页面,或者什么也不做。

KTHacks.java

 public final class KTHacks { private KTHacks() { throw new UnsupportedOperationException(); } /** * Forge a null into a platform type and take advantage of relaxed null-checks. * @param <T> * @return */ public static <T> T NULL() { return null; } } 

ReflectBackedProperty.kt

 import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty fun <T> reflect(instance: Any, initOnce: Boolean = true) = ReflectBackedProperty<T>(initOnce, instance) class ReflectBackedProperty<T>(val initOnce: Boolean, val instance: Any): ReadOnlyProperty<Any, T> { var initialized = false var cache: T = KTHacks.NULL() override operator fun getValue(thisRef: Any, property: KProperty<*>): T { @Suppress("UNCHECKED_CAST") if (!initialized || !initOnce) { cache = instance.javaClass.getDeclaredField(property.name).get(instance) as T initialized = true } return cache } } 

One Solution collect form web for “如何安全地解决这个空初始化器检查?”

一种方法是将T限制为仅具有上限的非空类型:

 class ReflectBackedProperty<T: Any> : ReadOnlyProperty<Any, T> {} 

另一种方法是不打扰lateinit的:

 class ReflectBackedProperty<T>(val initOnce: Boolean, val instance: Any): ReadOnlyProperty<Any, T> { var initialized = false var cache: T? = null override operator fun getValue(thisRef: Any, property: KProperty<*>): T { if (!initialized || !initOnce) { cache = instance.javaClass.getDeclaredField(property.name).get(instance) as T initialized = true } return cache as T } } 
  • Kotlin的crossinline和noinline有什么不同?
  • 运算符==不能应用于Kotlin中的“Long”和“Int”
  • 空条件检查
  • 匕首2,不能在我的活动中注入演示者
  • 用Gradle和Kotlin构建一个可执行的jar
  • 如何通过interceptTestCase来更改KotlinTest中的测试对象属性
  • 如何定义kotlin全球范围内的arralist
  • 自己的SDK架构 - Kotlin中的异步方法API
  • Kotlin:MyClass :: class.java vs this.javaClass
  • 在Rx中设置调度程序的顺序
  • Android回调和代码重用
  • Kotlin language will be the best programming language for Android.