Kotlin的初学者。
我尝试通过程序中的反射来创建和填充对象。我在纯kotlin中找不到相同的功能,所以我的解决方案类似于下面的代码工作正常,但需要使用像java.lang.String::class.java
和intelliJ这样的脏引用,可以理解,似乎并不喜欢这样。是否有一种更简单的方法可以解决这个问题呢?
val jclass = myObject::class.java
val setters = jclass.declaredMethods.filter { it.name.startsWith("set") }
for (s in setters) {
val paramType = s.parameterTypes.first()
val data = when(paramType) {
java.lang.Integer::class.java -> foo
java.lang.Double::class.java -> bar
java.lang.String::class.java -> baz
}
s.invoke(myObject, data)
}
答案 0 :(得分:10)
您可以使用Kotlin反射,这需要您将kotlin-reflect
添加为项目的依赖项。
如果您使用不同的Kotlin版本,可以在此处找到kotlin-reflect
for Kotlin 1.0.5或pick another version。
之后,您可以按如下方式重写代码:
val properties = myObject.javaClass.kotlin.memberProperties
for (p in properties.filterIsInstance<KMutableProperty<*>>()) {
val data = when (p.returnType.javaType) {
Int::class.javaPrimitiveType,
Int::class.javaObjectType -> foo
Double::class.javaPrimitiveType,
Double::class.javaObjectType -> bar
String::class.java -> baz
else -> null
}
if (data != null)
p.setter.call(myObject, data)
}
一些细节:
尽管使用了Kotlin反射,但这种方法也适用于Java类,它们的字段和访问器将被视为属性,如here所述。
与Java反射一样,memberProperties
返回此类型的public
属性及其所有超类型。要获取在类型中声明的所有属性(包括private
,但不是超类型中的属性),请改用declaredMemberProperties
。
.filterIsInstance<KMutableProperty<*>
仅返回可变属性,以便您稍后可以使用p.setter
。如果您需要迭代所有属性的getter,请将其删除。
在when
区块中,我将p.returnType.javaType
与Int::class.javaPrimitiveType
和Int::class.javaObjectType
进行了比较,因为Kotlin中的Int
可以是什么映射到Java int
或java.lang.Integer
,具体取决于其用法。在Kotlin 1.1中,只需检查p.returnType.classifier == Int::class
。
答案 1 :(得分:0)
如果需要获取属性获取器/设置器,则可以使用它的一些内置构造YourClass :: propertyName
看看下面的例子
fun main(args: Array<String>) {
val myObject = Cat("Tom", 3, 35)
println(Cat::age.getter.call(myObject)) // will print 3
Cat::age.setter.call(myObject, 45)
print(myObject) // will print Cat(name=Tom, age=45, height=35)
}
data class Cat(var name : String, var age : Int, val height : Int)
,但是有时您不完全了解类(使用泛型)或需要获取属性列表,然后使用val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T, *>>
它将返回所有属性,其中一些可以是可变的(var)且某些是不可变的(val),您可以通过检查属于KMutableProperty<*>
(通过使用is
运算符进行过滤或使用诸如filterIsInstance<KMutableProperty<*>>
之类的便捷方法)来找出不变性
关于您的代码段
我绝对同意热键,但是现在最好使用myObject::class.declaredMemberProperties
代替myObject.javaClass.kotlin.memberProperties
因为不推荐使用第二个
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html
data class Cat(var name : String, var age : Int, val height : Int)
@JvmStatic
fun main(args: Array<String>) {
val myObject = Cat("Tom", 3, 35)
val properties = myObject::class.declaredMemberProperties
for (p in properties.filterIsInstance<KMutableProperty<*>>()) {
val data = when (p.returnType.javaType) {
Int::class.javaPrimitiveType,
Int::class.javaObjectType -> 5
String::class.java -> "Rob"
else -> null
}
if (data != null)
p.setter.call(myObject, data)
}
println(myObject)
// it will print Cat(name=Rob, age=5, height=35),
// because height isn't var(immutable)
}
通常,考虑到这种构造,我会遇到类似的问题
val myObject = Cat("Tom", 3, 35)
Cat::class.declaredMemberProperties
//if we want only public ones
.filter{ it.visibility == KVisibility.PUBLIC }
// We only want strings
.filter{ it.returnType.isSubtypeOf(String::class.starProjectedType) }
.filterIsInstance<KMutableProperty<*>>()
.forEach { prop ->
prop.setter.call(myObject, "Rob")
}
println(myObject)
//it will print Cat(name=Rob, age=3, height=35),
//because name is only eligible in this case