我尝试将Map<String, Any>
转换为数据类示例:
data class Person(
val name: String,
val age: Int,
val weight: Double?,
)
fun test() {
val map = mapOf(
"name" to "steven",
"age" to 30,
"weight" to 60,
)
val ctor = Person::class.constructors.first();
val params = ctor.parameters.associateWith {
map[it.name]
}
val instance = ctor.callBy(params)
println(instance)
}
上面的代码抛出java.lang.IllegalArgumentException: argument type mismatch
,因为60
作为Int传递给weight
,而Kotlin不支持隐式转换。
然后将weight
的类型更改为不可空的Double
data class Person(
val name: String,
val age: Int,
val weight: Double, // !
)
这样就行了,甚至60F
也行。
我的问题是:
1.为什么隐式转换只在类型不可为空时起作用?
1.如何在类型可为空时进行隐式转换?
1条答案
按热度按时间q3qa4bjr1#
假设这是Kotlin/JVM。
在深入研究了
callBy
如何在JVM上实现之后,我发现它最终会调用Constructor.newInstance
。相关文档显示:单个参数会自动展开以匹配原始形式参数,并且原始参数和引用参数都需要进行方法调用转换。
当您在Kotlin中使用不可空的
Double
作为参数类型时,它会被转换为JVM世界中的原始类型double
。但是,如果使用可空类型Double?
,则会将其转换为引用类型 Package 器java.lang.Double
。这是因为基本类型double
不能为null。类似的情况发生在Int
和Int?
。newInstance
文档中提到的“方法调用转换”(我认为是指调用上下文中允许的转换列表)不包括从int
到java.lang.Double
的转换。毕竟,这段Java代码不会编译:但如果
foo
采用了double
原语,它将编译。至于你的第二个问题,我想不出比手动检查每个参数和参数类型,并为每种情况显式执行转换更好的方法。
如果可以更改
Person
,我建议添加一个接受不可空的Double
的二级构造函数,并更改调用代码以选择适当的构造函数。或者,如果你真的不喜欢选择构造函数,可以将现有的构造函数改为
Number?
,并在使用它之前使用toXXX
方法将其转换为适当的数值类型。