假设我需要设置由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)
}
但如果O是一个对象,我该怎么办?
答案 0 :(得分:7)
KClass
有一个objectInstance
字段:
Class.forName(ownerClassName).kotlin.objectInstance
这是Kotlin反思的内容。
返回:对象声明的实例,如果此类不是对象声明,则返回null。
如果KClass
使用forName
方法,这会更好,但遗憾的是does not(还),所以我们需要改为(Java)Class
并将其转换为KClass
。
您可以使用KClass
扩展程序属性从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)
这是一个有效的测试:
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
}
答案 1 :(得分:1)
object
被转换为一个带有私有构造函数和一个名为INSTANCE
的静态字段的类,其中在加载此类时存储唯一的实例,因此用{/ 1}替换Class.forName(ownerClassName).newInstance()
>
Class.forName(ownerClassName).getDeclaredField("INSTANCE").get(null)
应该有用。
的Javadoc: