Kotlin泛型ReadOnlyProperty委托as?安全类型转换失效问题
这不是Kotlin的bug,是JVM泛型类型擦除的正常表现。
问题原因
- JVM平台的泛型默认采用类型擦除实现,你声明的
ColorDelegate<T>中的泛型参数T未加reified实化修饰,运行时T的具体类型信息会被擦除,it as? T的类型检查逻辑无法正常执行,等价于it as? Any,所有元素都会通过检查,不会按预期过滤类型。 - 你遇到的
ClassCastException不是在as? T转换阶段抛出的,是在getValue方法返回结果后,由Kotlin编译器自动插入的隐式类型转换代码抛出的:你声明white属性的类型是White,但运行时返回了Black实例,隐式转换失败才触发异常。
修复方案
方案1:使用实化泛型(推荐)
因为类的泛型参数不能加reified修饰,我们可以用inline函数构造委托实例,传递实化的类型信息:
inline fun <reified T> colorDelegate() = object : ReadOnlyProperty<Palette, T> { override fun getValue(thisRef: Palette, property: KProperty<*>): T { // filterIsInstance依赖实化泛型自动实现类型过滤 return thisRef.colorCollection.list.filterIsInstance<T>().first() } } // Palette类修改为 class Palette { val black: Black by colorDelegate() val white: White by colorDelegate() val colorCollection = ColorCollection() }
方案2:利用属性信息校验类型
如果不想用inline函数,也可以直接通过委托方法传入的KProperty参数获取属性的目标类型做校验:
import kotlin.reflect.full.isInstance class ColorDelegate<T> : ReadOnlyProperty<Palette, T> { override fun getValue(thisRef: Palette, property: KProperty<*>): T { val targetType = property.returnType.classifier as KClass<*> return thisRef.colorCollection.list.first { targetType.isInstance(it) } as T } }
内容的提问来源于stack exchange,提问作者Arst
相关产品推荐
相关产品推荐

