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

调用Iterable<Int>.sum()处理字符串列表时,为何报错无法转为Number而非Int?

为什么泛型不安全转换后调用sum()会抛出Number类型转换异常?

先看这段存在问题的代码:

fun printSum(c: Collection<*>) {
    val intList = c as? List<Int> // 类型擦除导致无法检查List的元素类型
        ?: throw IllegalArgumentException("List is expected")
    println(intList.sum())
}

当传入字符串列表printSum(listOf("a", "b", "c"))时,抛出的异常是:

Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')

明明我们预期的是无法转换为Int,为什么报错提示无法转换为Number?

原因解析:

  1. 类型擦除的影响:c as? List<Int>在运行时只会检查c是否是List类型,不会验证元素的实际类型(因为泛型类型参数在JVM运行时会被擦除)。所以intList的静态类型是List<Int>,但实际运行时是List<String>。

  2. sum()函数的字节码实现:Kotlin标准库中Iterable<Int>.sum()的实现,编译为JVM字节码时,会先将遍历到的元素转换为Number类型,再拆箱为int进行累加。这是因为JVM中所有数值包装类(包括Integer)都继承自Number,这种实现可以复用部分逻辑。

当代码尝试从实际是String的列表中取出元素,执行checkcast java.lang.Number指令时,String并非Number的子类,因此直接抛出无法转换为Number的ClassCastException——因为转换检查发生在Number这一层,还没到具体的Integer类型检查环节。

验证:

如果手动模拟sum()的遍历逻辑:

fun printSumManual(c: Collection<*>) {
    val intList = c as? List<Int> ?: throw IllegalArgumentException("List is expected")
    var sum = 0
    for (element in intList) {
        sum += element // 这里的字节码会先尝试将element转成Number
    }
    println(sum)
}

调用printSumManual(listOf("a", "b", "c"))会抛出和之前完全一致的异常,因为遍历赋值的字节码逻辑和sum()函数一致。

内容的提问来源于stack exchange,提问作者Kirill

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:33:21