Kotlin - эффективный и масштабируемый способ получить значение свойства экземпляра класса по id или по строке - PullRequest
0 голосов
/ 02 марта 2019

Я хотел бы сделать свойства класса и его дочерних классов доступными во время выполнения для чтения и записи через целочисленный идентификатор или по имени свойства с производительностью, максимально приближенной к производительности обычного скомпилированного чтения или записи, насколько это возможно.,Может быть много экземпляров этого класса и его дочерних классов (скажем, до 1 миллиона), и каждый класс может иметь сотни свойств, поэтому я хочу минимизировать объем памяти, используемый каждым свойством в каждом экземпляре класса.

Широкие группы решений, которые я вижу, используют отражение, делают каждое свойство экземпляром изменяемого класса, а затем сохраняют его карты или пишут гигантские операторы 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)
                }
            }
        }
    }
}

1 Ответ

0 голосов
/ 02 марта 2019

Я не думаю, что вы получите желаемую производительность от отражения.

(Reflection не был предназначен для высокопроизводительного использования - и, по моему опыту, очень редко используется в производственном кодеОн отлично подходит для тестирования, фреймворков, инструментов сборки и т. Д., Но в большинстве вопросов, которые я вижу по этому поводу, реальный ответ - использовать лучший дизайн, не требующий отражения!)

Ни один изДругие два подхода, конечно, идеально.Это, вероятно, зависит от точных требований.Должны ли они вообще быть объектами с именованными свойствами Kotlin или они могут быть простыми картами?Последний может быть проще для кода и проще в обслуживании.Иначе жестко закодированные тесты, вероятно, сэкономят память.

(Если у вас было много времени, вы могли бы написать какой-то инструмент для сборки, который мог бы автоматически генерировать метод поиска с этими жестко закодированными тестами для вас. То, что будет использовать отражение, конечно, но только во время компиляции. Хотя это будет большая работа, и я не знаю, как вы к ней подходите.)

...