如何通过反射使用Kotlin对象

ssu*_*ukk 6 reflection kotlin

假设我需要设置由String反射给出的Kotlin对象O中的String给出的属性A. 如果O是一个班级我可以做这样的事情(忽视它没有意义):

fun setValue(ownerClassName: String, fieldName: String, value : Any) {
    val enclosingClass = Class.forName(ownerClassName).newInstance()
    val enclosingClassField = enclosingClass.javaClass.getDeclaredField(fieldName)
    enclosingClassField.isAccessible = true
    enclosingClassField.set(enclosingClass, value)
}
Run Code Online (Sandbox Code Playgroud)

但是如果O是一个对象,我该怎么做呢?

Moi*_*ira 10

KClass有一个objectInstance领域:

Class.forName(ownerClassName).kotlin.objectInstance
Run Code Online (Sandbox Code Playgroud)

这是Kotlin反思的内置.

返回:对象声明的实例,如果此类不是对象声明,则返回 null.

如果KClass有一个forName方法,这会更好,但遗憾的是它还没有(但是),所以我们需要获得(Java)Class并将其转换为KClass.

您可以使用extension属性KClass从a 获取实例.Class.kotlin

然后,您可以继续使用其余代码.我将其转换为Kotlin的反射库:

val kClass = Class.forName(ownerClassName).kotlin
// Get the object OR a new instance if it doesn't exist
val instance = kClass.objectInstance ?: kClass.java.newInstance()

val member = kClass.memberProperties
// Has to be a mutable property, otherwise we can't set it
        .filterIsInstance<KMutableProperty<*>>()
// Check the name
        .filter { it.name == fieldName }
        .firstOrNull()

// Set the property
member?.setter?.call(instance, value)
Run Code Online (Sandbox Code Playgroud)

这是一个工作测试:

object TestObject {
    var field = 3
}

fun setValue(ownerClassName: String, fieldName: String, value: Any) {
    val kClass = Class.forName(ownerClassName).kotlin
    val instance = kClass.objectInstance ?: kClass.java.newInstance()

    val member = kClass.memberProperties.filterIsInstance<KMutableProperty<*>>()
            .firstOrNull { it.name == fieldName }

    member?.setter?.call(instance, value)
}

fun main(args: Array<String>) {
    println(TestObject.field) // 3
    setValue("some.package.TestObject", "field", 4)
    println(TestObject.field) // 4
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*nov 8

object被翻译成一个带有私有构造函数和一个静态字段的INSTANCE类,当这个类被加载时,唯一的实例存储在这个字段中,因此替换Class.forName(ownerClassName).newInstance()

Class.forName(ownerClassName).getDeclaredField("INSTANCE").get(null)
Run Code Online (Sandbox Code Playgroud)

应该管用。


Javadoc: