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

Kotlin自定义RollingWindow类数组赋值变量时触发ClassCastException

问题触发原因

  • 本质是Kotlin泛型擦除和数组具体化类型特性共同作用的结果:你在toArray方法里加的@Suppress("UNCHECKED_CAST")只在编译期生效,忽略了类型转换警告,运行时你返回的Array<T>本质还是Array<Any?>(JVM层面对应Object数组),没有真的转换成对应泛型的数组类型。
  • 两种调用场景的差异:
    直接把toArray()返回值传入assertArrayEquals时,该方法的参数默认匹配Array<Any?>重载,编译器不会插入额外的类型校验逻辑,运行时不会触发转换所以没有报错;
    当你主动把返回值赋值给Array<Double>这类具体类型的数组变量时,Kotlin编译器会在赋值行自动插入隐形的类型强转校验代码,运行时JVM发现实际返回的是Object数组,无法转成Double数组,就会抛出ClassCastException。

修复方案

可以根据使用场景选择以下任意一种方案:

方案1:构造数组时传入泛型类引用,生成对应类型的数组

修改RollingWindow构造函数,接收泛型对应的KClass参数,toArray时通过反射构造对应类型的数组,避免无意义的强转:

class RollingWindow<T>(private val maxSize: Int, private val tClass: KClass<T>) {
    private val buffer = arrayOfNulls<Any?>(maxSize)
    // 省略push等原有逻辑

    fun toArray(): Array<T> {
        val targetArray = java.lang.reflect.Array.newInstance(tClass.java, buffer.size) as Array<T>
        // 拷贝buffer中的有效数据到目标数组
        buffer.copyInto(targetArray)
        return targetArray
    }
}

// 调用示例
val window = RollingWindow<Double>(10, Double::class)

方案2:用reified泛型简化调用

如果不想每次手动传类引用,可以增加内联的reified泛型构造方法:

class RollingWindow<T> private constructor(
    private val maxSize: Int,
    private val tClass: KClass<T>
) {
    companion object {
        inline operator fun <reified T> invoke(maxSize: Int): RollingWindow<T> {
            return RollingWindow(maxSize, T::class)
        }
    }
    // 其他逻辑和方案1一致
}

// 调用示例,无需手动传入类引用
val window = RollingWindow<Double>(10)

方案3:返回List替代Array

如果业务上不需要强类型数组,直接返回List可以避免数组的类型校验问题,不需要额外处理类引用:

fun toList(): List<T> {
    // 按实际业务逻辑过滤有效数据后返回
    return buffer.filterNotNull().map { it as T }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 14:12:00