Kotlin中如何实现泛型超类元素列表及统一处理函数?
解决泛型FilledBowl的统一列表处理问题
问题重现
我有一组继承自Fruit的子类:
open class Fruit() {} class Apple() : Fruit() {} class Orange() : Fruit() {}
为了对不同水果的碗执行逻辑统一但实现不同的操作,我采用了泛型抽象类方案:
// 修正原代码的泛型语法错误后 abstract class FilledBowl<F : Fruit> { abstract var fruits: MutableList<F> abstract fun makeJuice(fruit: F) } class AppleFilledBowl : FilledBowl<Apple>() { override var fruits = mutableListOf<Apple>() override fun makeJuice(fruit: Apple) { // 苹果榨汁实现 } } class OrangeFilledBowl : FilledBowl<Orange>() { override var fruits = mutableListOf<Orange>() override fun makeJuice(fruit: Orange) { // 橙子榨汁实现 } }
但无法声明一个能处理所有FilledBowl实例列表的函数;尝试去掉泛型的方案又会出现类型不兼容问题:
abstract class FilledBowl() { abstract var fruits: MutableList<Fruit> abstract fun makeJuice(fruit: Fruit) } // 此处会报错:MutableList<Apple>无法覆盖MutableList<Fruit>,makeJuice参数也不匹配 class AppleFilledBowl() : FilledBowl() { override var fruits: MutableList<Apple> = mutableListOf() override fun makeJuice(fruit: Apple) { // 实现 } }
解决方案
方案一:通过非泛型上层接口实现统一处理
核心思路是定义一个不带泛型的接口,让泛型FilledBowl继承它,把具体类型的逻辑封装在子类内部,上层只需要调用统一的入口方法:
// 定义非泛型接口,提供统一处理入口 interface FruitBowl { fun processAllFruits() } // 泛型抽象类实现接口,封装通用逻辑 abstract class FilledBowl<F : Fruit> : FruitBowl { abstract var fruits: MutableList<F> abstract fun makeJuice(fruit: F) // 统一处理逻辑,内部调用子类的具体实现 override fun processAllFruits() { fruits.forEach { makeJuice(it) } } } // 子类实现保持不变 class AppleFilledBowl : FilledBowl<Apple>() { override var fruits = mutableListOf<Apple>() override fun makeJuice(fruit: Apple) { println("榨苹果汁") } } class OrangeFilledBowl : FilledBowl<Orange>() { override var fruits = mutableListOf<Orange>() override fun makeJuice(fruit: Orange) { println("榨橙汁") } } // 现在可以轻松处理所有FruitBowl实例的列表 fun process(bowls: MutableList<FruitBowl>) { bowls.forEach { it.processAllFruits() } } // 调用示例 fun main() { val appleBowl = AppleFilledBowl().apply { fruits.add(Apple()) } val orangeBowl = OrangeFilledBowl().apply { fruits.add(Orange()) } process(mutableListOf(appleBowl, orangeBowl)) }
方案二:使用泛型通配符直接处理列表
如果不想新增接口,可以用泛型通配符out声明列表类型,同时让子类封装内部元素的处理逻辑:
// 泛型抽象类不变,新增内部处理方法 abstract class FilledBowl<F : Fruit> { abstract var fruits: MutableList<F> abstract fun makeJuice(fruit: F) fun processBowl() { fruits.forEach { makeJuice(it) } } } // 处理函数用通配符接受所有FilledBowl子类 fun process(bowls: MutableList<out FilledBowl<*>>) { bowls.forEach { it.processBowl() } }
为什么非泛型方案不可行?
- MutableList的不变性:
MutableList<Apple>不是MutableList<Fruit>的子类——因为MutableList是不变类型(既不支持协变out也不支持逆变in),如果允许替换,可能会往MutableList<Apple>中添加Orange实例,导致类型错误。如果是只读的List<out Fruit>,则可以支持协变。 - 违反里氏替换原则:子类的
makeJuice(fruit: Apple)无法覆盖父类的makeJuice(fruit: Fruit)——父类方法能接受任何Fruit子类,子类却只能接受Apple,用父类引用调用方法时传入Orange会导致运行时错误。
内容的提问来源于stack exchange,提问作者Wesley Cramer
相关产品推荐
相关产品推荐

