You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 23:05:28