如何在运行时仅知道属性名的情况下读取 Kotlin 数据类实例中属性的值?
下面是一个函数,可以从类的实例中读取属性名称(如果未找到属性,则会抛出异常,但您可以更改该行为):
import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberProperties
@Suppress("UNCHECKED_CAST")
fun <R> readInstanceProperty(instance: Any, propertyName: String): R {
val property = instance::class.members
// don't cast here to <Any, R>, it would succeed silently
.first { it.name == propertyName } as KProperty1<Any, *>
// force a invalid cast exception if incorrect type here
return property.get(instance) as R
}
dependencies {
implementation(kotlin("reflect"))
}
// some data class
data class MyData(val name: String, val age: Int)
val sample = MyData("Fred", 33)
// and reading property "name" from an instance...
val name: String = readInstanceProperty(sample, "name")
// and reading property "age" placing the type on the function call...
val age = readInstanceProperty<Int>(sample, "age")
println(name) // Fred
println(age) // 33
instance::class.members
代替instance.javaClass.kotlin.declaredMemberProperties
,但应检查属性的类型是否为KProperty<*,*>
或KMutableProperty<*,*>
。请注意不要改变原意。 - outisException:java.lang.IllegalAccessException
)方面遇到问题,请尝试访问此链接:https://dev59.com/zVYM5IYBdhLWcg3w-Dpf#48159066 - Reejesh PKval name = obj.javaClass
.getMethod("getName") // to get property called `name`
.invoke(obj)
你甚至可以创建一个扩展函数:
inline fun <reified T : Any> Any.getThroughReflection(propertyName: String): T? {
val getterName = "get" + propertyName.capitalize()
return try {
javaClass.getMethod(getterName).invoke(this) as? T
} catch (e: NoSuchMethodException) {
null
}
}
getDeclaredMethod
和setAccessible
修改此代码。这也适用于具有相应getter的Java对象(但它缺少boolean
的is
和has
getter的约定)。data class Person(val name: String, val employed: Boolean)
val p = Person("Jane", true)
val name = p.getThroughReflection<String>("name")
val employed = p.getThroughReflection<Boolean>("employed")
println("$name - $employed") // Jane - true
kotlin-reflect
库,你需要将其单独添加到你的项目中,这是它的文档。它将让你获取实际的Kotlin属性值,忽略Java的getter方法。javaClass.kotlin
来获取实际的Kotlin类令牌,然后从中获取属性。val name = p.javaClass.kotlin.memberProperties.first { it.name == "name" }.get(p)
Boolean
属性生成了名为getSomething
的方法,而不是isSomething
。 - hotkey@JvmField
注解来省略setter和getter。 - Vlad以上的答案对我没有用,所以我创建了一个扩展函数来解决这个问题:
@Throws(IllegalAccessException::class, ClassCastException::class)
inline fun <reified T> Any.getField(fieldName: String): T? {
this::class.memberProperties.forEach { kCallable ->
if (fieldName == kCallable.name) {
return kCallable.getter.call(this) as T?
}
}
return null
}
val valueNeeded: String? = yourObject.getField<String>("exampleFieldName")
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
我想知道是否可以通过编程来定义字段的类型。您可以轻松地获取类型:
kCallable.returnType
getField<String>
替代
getField<kCallable.returnType>
编辑:
我最终使用了以下内容:when (prop.call(object)) {
is ObservableList<*> -> {}
is Property<*> -> {}
}