Kotlin:如何按泛型抽象类的泛型参数进行过滤?
Kotlin泛型基类中使用
filterIsInstance<T>()报错的解决方法 问题场景
你有一个带受限类型参数<T: Shape>的泛型抽象基类,尝试用filterIsInstance<T>()筛选集合时遇到错误:
Cannot use 'T' as reified type parameter. Use a class instead
原代码如下:
abstract class ShapeContainer<T: Shape>(val shapeConsumer: Consumer) { val shapes : List<T> init { shapes = shapeConsumer.consume().filterIsInstance<T>() } } class SquareContainer(consumer) : ShapeContainer<Square>(consumer) { val squares : List<Square> = shapes }
原因
Kotlin泛型存在类型擦除机制,非reified(具体化)的类型参数T在运行时无法获取具体类型信息,而filterIsInstance<T>()需要运行时类型信息才能完成筛选,因此触发报错。
解决方案
方案一:显式传入Class<T>参数
在基类构造函数中添加Class<T>参数,使用filterIsInstance的重载版本(接收Class<T>参数)完成类型筛选:
abstract class ShapeContainer<T : Shape>( val shapeConsumer: Consumer, private val type: Class<T> ) { val shapes: List<T> init { shapes = shapeConsumer.consume().filterIsInstance(type) } } // 子类实现时传入具体类型的Class实例 class SquareContainer(consumer: Consumer) : ShapeContainer<Square>(consumer, Square::class.java) { val squares: List<Square> = shapes }
方案二:使用inline reified函数实现初始化
如果不想显式传递Class<T>,可以借助inline reified函数的特性,通过工厂方法完成集合初始化:
abstract class ShapeContainer<T : Shape> protected constructor( val shapeConsumer: Consumer, val shapes: List<T> ) { // 伴生对象提供通用工厂方法 companion object { inline fun <reified T : Shape> create(consumer: Consumer): ShapeContainer<T> { val filteredShapes = consumer.consume().filterIsInstance<T>() return object : ShapeContainer<T>(consumer, filteredShapes) {} } } } // 自定义子类的实现方式 class SquareContainer private constructor(consumer: Consumer, shapes: List<Square>) : ShapeContainer<Square>(consumer, shapes) { companion object { fun create(consumer: Consumer) = SquareContainer(consumer, consumer.consume().filterIsInstance<Square>()) } } // 使用示例 val squareContainer = SquareContainer.create(yourConsumerInstance)
方案对比
- 方案一:逻辑直观,适合需要自定义多个子类的场景,代码可读性高。
- 方案二:避免了显式传递
Class对象,但需要通过工厂方法创建实例,适合不需要大量自定义子类的场景。
内容的提问来源于stack exchange,提问作者Abbas Gadhia
相关产品推荐
相关产品推荐

