Kotlin继承泛型基接口时泛型默认推断为out类型原因咨询
问题根因
不存在“子接口继承基接口时泛型默认被推断为out协变”的规则,你遇到的现象是不变泛型的类型匹配规则、Kotlin数组类型推断的自动投影机制共同导致的:
- 未加
in/out修饰符的泛型是不变型:若A是B的子类型,GenericType<A>和GenericType<B>没有继承关系,无法直接互相赋值。 - 你定义的
FeaturedTestAdapterContract.Presenter继承的是SubPresenter<FeaturedTestAdapterContract.View>,而这个子接口内的View是FeaturedCardAdapterContract.View的子类型,也就是说Presenter的真实类型是SubPresenter<子View>,而非SubPresenter<顶层View>。 - 当你尝试把两个
Presenter实例存入Array<SubPresenter<顶层View>>时,受不变泛型规则限制,SubPresenter<子View>不属于SubPresenter<顶层View>的子类型,直接赋值会触发类型不匹配错误。 - 此时Kotlin类型推断会自动寻找两个元素的公共父类型做适配,最终匹配到
SubPresenter<out 顶层View>:协变投影规则下,SubPresenter<子View>是SubPresenter<out 顶层View>的合法子类型,因此声明数组为out投影或*星投影时可以正常编译。但协变投影本身就禁止调用以泛型类型为入参的方法(避免类型安全漏洞:数组内的Presenter实际只支持绑定的具体子View,无法保证能接受任意顶层View实例),这就是onBind调用失败的直接原因。
问题复现代码
interface FeaturedCardAdapterContract { interface View { fun onCreate() } interface SubPresenter<V : View> { fun onBind(v: V) } } interface FeaturedTestAdapterContract { interface View : FeaturedCardAdapterContract.View interface Presenter : FeaturedCardAdapterContract.SubPresenter<View> } fun main() { val featureImpl1: FeaturedTestAdapterContract.Presenter = object : FeaturedTestAdapterContract.Presenter { override fun onBind(v: FeaturedCardAdapterContract.View) {} } val featureImpl2: FeaturedTestAdapterContract.Presenter = object : FeaturedTestAdapterContract.Presenter { override fun onBind(v: FeaturedCardAdapterContract.View) {} } // 编译通过:out协变投影可匹配子泛型类型 val interfaceArray1: Array<FeaturedCardAdapterContract.SubPresenter<out FeaturedCardAdapterContract.View>> = arrayOf(featureImpl1, featureImpl2) // 编译失败:不变泛型下SubPresenter<子View>不属于SubPresenter<顶层View>的子类型 // val interfaceArray2: Array<FeaturedCardAdapterContract.SubPresenter<FeaturedCardAdapterContract.View>> = arrayOf(featureImpl1, featureImpl2) // 编译通过:星投影等价于out 上界投影 val interfaceArray3: Array<FeaturedCardAdapterContract.SubPresenter<*>> = arrayOf(featureImpl1, featureImpl2) for (featureImpl in interfaceArray3) { // 编译失败:协变/星投影下禁止调用泛型作为入参的方法,避免类型安全问题 // featureImpl.onBind(object : FeaturedCardAdapterContract.View { // override fun onCreate() {} // }) } }
修复方案
根据业务场景二选一即可:
- 如果要求所有Presenter实例都能处理顶层
FeaturedCardAdapterContract.View,直接修改子接口的泛型绑定为顶层View:
修改后interface Presenter : FeaturedCardAdapterContract.SubPresenter<FeaturedCardAdapterContract.View>Presenter本身就是SubPresenter<顶层View>类型,无需额外投影即可直接存入数组,onBind方法也可正常调用。 - 如果
SubPresenter的泛型参数V只会作为方法入参使用(即Presenter是V的消费者),直接给基接口泛型加上in逆变修饰符:
逆变规则下,interface SubPresenter<in V : View> { fun onBind(v: V) }SubPresenter<子View>天然是SubPresenter<父View>的子类型,无需额外投影即可直接赋值,也不会影响入参方法的正常调用。
内容的提问来源于stack exchange,提问作者Prateek Kumar
相关产品推荐
相关产品推荐

