Kotlin反射中Int转可空Double隐式转换失败的原因与解决方法
Kotlin Map转数据类:可空参数类型转换问题
问题背景
尝试将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,原因是Int类型的60无法直接传给Double?参数。但将weight改为非空Double后,代码可正常运行,甚至传入60F也能自动转换。
问题解答
1. 为何隐式转换仅在参数非空时生效?
这和Kotlin反射callBy的参数处理逻辑直接相关:
- 非空基本类型(如
Double)对应JVM原始类型double,JVM本身支持原始类型间的隐式转换(比如int转double、float转double),callBy会自动触发这个转换逻辑。 - 可空类型
Double?对应JVM的包装类java.lang.Double,你传入的60是Int(对应java.lang.Integer),包装类之间不存在自动隐式转换的逻辑,Kotlin反射不会帮你做这个转换,因此抛出类型不匹配异常。
2. 可空参数类型下如何实现隐式转换?
需要手动在参数映射阶段添加类型转换逻辑,根据目标参数的类型对map中的值做针对性转换。示例代码如下:
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, // Int类型值 // 也可以测试Float值:"weight" to 60F ) val ctor = Person::class.constructors.first() val params = ctor.parameters.associateWith { param -> val value = map[param.name] // 根据参数类型处理转换 when (param.type) { // 匹配可空Double类型 Double::class.createType(nullable = true) -> { when (value) { is Number -> value.toDouble() // 统一处理所有数字类型转Double else -> value // 非数字类型或null直接返回 } } // 可添加其他需要转换的类型,比如可空Int等 Int::class.createType(nullable = true) -> { (value as? Number)?.toInt() ?: value } else -> value } } val instance = ctor.callBy(params) println(instance) // 输出:Person(name=steven, age=30, weight=60.0) }
如果需要更通用的转换逻辑,可以封装一个工具函数,批量处理所有数字类型到目标可空类型的转换,减少重复代码。
内容的提问来源于stack exchange,提问作者zwlxt
相关产品推荐
相关产品推荐

