Kotlin:覆盖子类型中的泛型属性

时间:2016-02-16 11:24:15

标签: generics override kotlin

我尝试编写一些通用代码,但无法解决Type of 'PROPERTY' is not a subtype of the overridden property错误。

我的代码的简化版本:

abstract class BaseP<V> {
    var view: V? = null
}

abstract class BaseF {
    fun smth() {
        pp.view = this
    }
    abstract val pp: BaseP<BaseF>
}

abstract class SubF: BaseF() {
    abstract override val pp: BaseP<SubF>
    // Error:(20, 30) Type of 'pp' is not a subtype of the overridden property 'public abstract val pp: BaseP<BaseF> defined in BaseF'
}

我发现错误可能是@Suppress - 但我怀疑这是最好的也是唯一的方法。还有更好的东西吗?

毕竟我无法理解,为什么subtypeA<subtypeB>并不算作baseA<baseB>的子类型,有人可以解释一下吗?

1 个答案:

答案 0 :(得分:8)

首先,SubtypeA<B>BaseA<B>的子类型,因此问题出在通用参数子类型中。

答案在于Kotlin generics variance,与that of Java类似。

  

为什么SubtypeA<SubtypeB>不计算BaseA<BaseB>的子类型?

默认情况下,泛型是不变的,这意味着,即使在更简单的情况下,对于类A<T>A<SubtypeB>A<BaseB>也不是彼此的子类型,除非另有说明方差修饰符inout(或Java wildcards)。

可能有两种情况:

  • 如果您只想从您的班级T的实例中获取 A个实例,那么您可以使用out修饰符:{{ 1}}。

    此处A<out T>成为A<SubtypeB>的子类型,因为从A<BaseB>开始,您显然可以采用A<SubtypeB>的实例,反之亦然。

  • 如果您只想传递 BaseB进入您的班级&#39;方法,然后在类声明中使用T修饰符:in

    此处A<in T>A<BaseB>的子类型,因为A<SubtypeB>的每个实例也可以在方法中接收A<BaseB>,但反之亦然。

如果你们都传递SubtypeB来自你的T课程,那么A<T>的唯一选择是不变的,所以T也不是A<SubB>A<SuperB>的子类型:否则会导致与上述内容相矛盾。

情况确实如此:在A<B>中,您正在使用BaseP<B>项并将其放入V属性,因此view只能是不变的,V不是BaseP<SubF>的子类型,BaseP<BaseF>也不是。