我想成为一类的属性,并且它的子类可在运行时可用,用于通过Integer ID或用属性的名称读写,并以绩效与绩效一样接近常规编译的读写或写作是可行的。该课程可能有很多实例,它的子类(例如最多100万),每个类可能都有数百个属性,因此我想最大程度地减少每个类实例中每个属性使用的内存。
我看到的广泛的解决方案组正在使用反射,使每个属性成为可变类的实例,然后保留这些属性的图,或者在语句时写巨人。
我已经测试了反射实现的性能(见下文)。这需要直接访问我的测试中的属性的15倍。
可以改进,还是有更好的方法来做到这一点?
class ReflectionClass {
@FieldId(1)
var intField = 0
fun getPropById(id: Int): Any? {
val property = propertiesById[id]
return property?.get(this)
}
fun setIntPropById(id: Int, value: Int) {
val property = propertiesById[id]
if (property is KMutableProperty1) {
property?.setter?.call(this, value)
}
}
fun getPropByName(name: String): Any? {
val property = propertiesByName[name]
return property?.get(this)
}
fun setIntPropByName(name: String, value: Int) {
val property = propertiesByName[name]
if (property is KMutableProperty1) {
property as KMutableProperty1<ReflectionClass, Int>
property.set(this, value)
}
}
companion object {
//private val propertiesById = HashMap<Int, KProperty1<ReflectionClass,*>>()
private val propertiesById = HashMap<Int, KProperty1<ReflectionClass, *>?>()
private val propertiesByName = HashMap<String, KProperty1<ReflectionClass, *>>()
init {
val fields = ReflectionClass::class.memberProperties.forEach { property ->
val id = property.findAnnotation<FieldId>()
if (id != null) {
propertiesById.put(id.id, property)
propertiesByName.put(property.name, property)
}
}
}
}
}
我认为您不会从反射中获得想要的性能。
(反思不是为高性能使用而设计的 - 根据我的经验,很少在生产代码中使用。这非常适合测试,框架,构建工具等。但是在我看到的大多数问题中它的真正答案是使用不需要反射的更好设计!)
当然,其他两种方法都不是完美的。这可能取决于确切的要求。这些是否需要完全是具有命名Kotlin属性的对象,还是可以一直是简单的地图?后者可能更简单地代码,并且更易于维护。否则硬编码的测试可能会节省内存。
(如果您有很多时间,您可能会考虑编写某种构建工具,该工具可以自动使用这些硬编码的测试生成查找方法。将使用反射,当然,但是只有在编译时。但是,这是一项艰巨的工作,我不知道您将如何处理。)