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

Kotlin开发Android时无法用继承的Presenter重写父类presenter属性怎么办

问题原因

错误本质是Kotlin泛型的不变性约束:你在基类ListFragment中定义presenter的类型时,将ListPresenter的第二个泛型参数固定为ListFragment<ItemType, Adapter>,而子类重写时传入的是ContactsFragment。虽然ContactsFragment是ListFragment<Contact, ContactsAdapter>的子类,但默认情况下ListPresenter<Contact, ContactsFragment>和ListPresenter<Contact, ListFragment<Contact, ContactsAdapter>>不存在继承关系,因此触发类型不匹配错误。

解决方案

方案1:给基类增加自身泛型参数(最稳妥,推荐)

修改ListFragment定义,增加第三个泛型参数指代自身类型,让presenter的泛型和子类实际类型绑定,强转逻辑因为子类泛型参数必然是自身,所以完全安全:

// 增加第三个泛型参数F,约束为当前ListFragment的子类
abstract class ListFragment<ItemType, Adapter : ListAdapter<ItemType>, F : ListFragment<ItemType, Adapter, F>> : BaseFragment(),
ListContract.View<ItemType> {

    // presenter的第二个泛型参数改为F,绑定子类实际类型
    protected open val presenter: ListPresenter<ItemType, F> by lazy {
        ListPresenter(this as F)
    }
...
}

修改ContactsFragment的继承声明,传入自身作为第三个泛型参数即可:

// 第三个泛型参数填ContactsFragment自身
class ContactsFragment : ListFragment<Contact, ContactsAdapter, ContactsFragment>(), ContactsContract.View {

    // 此时重写的presenter类型完全匹配,不会报错
    override val presenter: ContactsPresenter<ContactsFragment> by lazy { ContactsPresenter(this) }
...
}

方案2:给ListPresenter的View泛型添加协变修饰

如果不想改动基类的泛型参数,且你的ListPresenter中没有把V类型作为方法入参使用的场景,可以给ListPresenter的第二个泛型参数加out关键字声明协变:

// 第二个泛型参数加out修饰,声明协变
open class ListPresenter<ItemType, out V : ListContract.View<ItemType>>(view: V) : BasePresenter<V>(view),
ListContract.Presenter<ItemType, V> {
...
}

修改后ListPresenter<Contact, ContactsFragment>会被自动识别为ListPresenter<Contact, ListFragment<Contact, ContactsAdapter>>的子类,类型错误直接消失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:18:01