1

我想让一个类的属性及其子类在运行时通过整数 id 或属性名称进行读写,其性能尽可能接近常规编译的读写。这个类可能有很多实例,它的子类(最多 100 万个),每个类可能有数百个属性,所以我想最小化每个类实例中每个属性使用的内存。

我看到的广泛的解决方案组正在使用反射,使每个属性成为可变类的实例,然后保留这些映射,或者编写巨大的 when 语句。

我已经测试了反射实现的性能(见下文)。在我的测试中,这需要 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)
                }
            }
        }
    }
}
4

1 回答 1

0

我不认为你会从反思中得到你想要的表现。

(反射不是为高性能使用而设计的——根据我的经验,它很少用于生产代码。它非常适合测试、框架、构建工具等;但在我看到的大多数关于它的问题中,真正的答案是使用不需要反射的更好设计!)

当然,其他两种方法都不是完美的。这可能取决于确切的要求。这些是否需要是具有命名 Kotlin 属性的对象,或者它们可以一直是简单的映射?后者可能更易于编码且更易于维护。其他硬编码测试可能会节省内存。

(如果您有很多时间,您可能会考虑编写某种构建工具,该工具可以自动为您生成带有这些硬编码测试的查找方法。 当然,将使用反射,但仅限于编译时。它不过,这将是一份大工作,我不知道你会如何处理它。)

于 2019-03-02T09:20:08.590 回答