Kotlin 数据 class:如果我在编译时不知道它的名字,如何读取 属性 的值?
Kotlin data class: how to read the value of property if I don't know its name at compile time?
如果 属性 名称仅在运行时已知,我如何在 Kotlin 数据 class 实例中读取 属性 的值?
可以通过reflection来实现,数据class和普通数据都一样。
第一个选项就是使用Java反射:
val 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
}
}
它调用public getter。要获取私有 属性 的值,您可以使用 is
的 getDeclaredMethod
and setAccessible
. This will also work for Java objects with the corresponding getters (but it misses the convention 和 boolean
的 has
getters 修改此代码)。 =24=]
和用法:
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
library which you should add to your project separately, here's its documentation。它会让你得到实际的 Kotlin 属性 值,忽略 Java getters.
您可以使用 javaClass.kotlin
获取实际的 Kotlin class 令牌,然后从中获取 属性:
val name = p.javaClass.kotlin.memberProperties.first { it.name == "name" }.get(p)
此解决方案仅适用于 Kotlin classes,不适用于 Java,但如果您需要使用 Kotlin classes,它会更可靠:它不会' 取决于底层实现。
这是一个从 class 的实例中读取 属性 的函数,给定 属性 名称( 如果 属性 不存在则抛出异常已找到,但您可以更改该行为):
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
}
build.gradle.kts
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
上面的答案对我不起作用,所以我为此创建了一个扩展函数:
@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")
同时将此添加到您应用的 build.gradle:
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
我想知道是否可以通过编程方式定义字段的类型。您可以通过以下方式轻松获取类型:
kCallable.returnType
但是您仍然必须明确指定通用类型:
getField<String>
而不是
getField<kCallable.returnType>
编辑:
我最终使用了以下内容:
when (prop.call(object)) {
is ObservableList<*> -> {}
is Property<*> -> {}
}
如果 属性 名称仅在运行时已知,我如何在 Kotlin 数据 class 实例中读取 属性 的值?
可以通过reflection来实现,数据class和普通数据都一样。
第一个选项就是使用Java反射:
val 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
}
}
它调用public getter。要获取私有 属性 的值,您可以使用 is
的 getDeclaredMethod
and setAccessible
. This will also work for Java objects with the corresponding getters (but it misses the convention 和 boolean
的 has
getters 修改此代码)。 =24=]
和用法:
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
library which you should add to your project separately, here's its documentation。它会让你得到实际的 Kotlin 属性 值,忽略 Java getters.
您可以使用 javaClass.kotlin
获取实际的 Kotlin class 令牌,然后从中获取 属性:
val name = p.javaClass.kotlin.memberProperties.first { it.name == "name" }.get(p)
此解决方案仅适用于 Kotlin classes,不适用于 Java,但如果您需要使用 Kotlin classes,它会更可靠:它不会' 取决于底层实现。
这是一个从 class 的实例中读取 属性 的函数,给定 属性 名称( 如果 属性 不存在则抛出异常已找到,但您可以更改该行为):
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
}
build.gradle.kts
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
上面的答案对我不起作用,所以我为此创建了一个扩展函数:
@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")
同时将此添加到您应用的 build.gradle:
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
我想知道是否可以通过编程方式定义字段的类型。您可以通过以下方式轻松获取类型:
kCallable.returnType
但是您仍然必须明确指定通用类型:
getField<String>
而不是
getField<kCallable.returnType>
编辑: 我最终使用了以下内容:
when (prop.call(object)) {
is ObservableList<*> -> {}
is Property<*> -> {}
}