为什么通用超类型声明不允许引用子类型对象?

时间:2019-08-08 02:45:08

标签: generics kotlin polymorphism covariance

我想知道为什么泛型超类型参数不允许引用子类型对象的背景。

abstract class Pet()

class Cat: Pet()

interface Retailer<T> {
    fun sell(): T
}

class CatRetailer: Retailer<Cat> {
    override fun sell(): Cat {
        println("Sell Cat")
        return Cat()
    }
}

// Type MismatchError prior to compilation  
val steveIrwinTheAnimalEnslaver: Retailer<Pet> = CatRetailer() 

变量定义会导致类型不匹配错误,编译器期望该类型为Retailer<Pet>

但是,PetCat的超类型。为什么多态性不能像下面那样工作?

open class SuperClassName() {}

class SubClassName : SuperClassName()

var variableName: SuperClassName = SubClassName()

2 个答案:

答案 0 :(得分:1)

您写道: class CatRetailer: Retailer<Cat> 为了使代码正常工作,您需要编写: class CatRetailer: Retailer<Pet>

Cat零售商没有实现pet的接口,而是实现了cat的接口。如果它将实现pet的接口,则可以编写: val steveIrwinTheAnimalEnslaver: Retailer<Pet>

在实现 cat 的界面时,您是说零售商的类型为 cat ,并且仅是cat。

Cat类型的接口扩展/实现Pet类型的接口。

这不是您通过子类给出的示例的情况。

总结:即使B扩展了A,Interface<B>也不是interface<A>。 但是B是A。

我希望足够清楚。

答案 1 :(得分:1)

PetCat的超类型,但是Retailer<Pet>并非Retailer<Cat>的超类型。看看为什么想象您添加了一个方法:

abstract class Pet()

class Cat: Pet()
class Dog: Pet()

interface Retailer<T> {
    fun sell(): T
    fun buy(x: T): Unit
}

// only really knows how to buy cats
val steveIrwinTheAnimalEnslaver: Retailer<Pet> = CatRetailer() 

// legal for any Retailer<Pet>
steveIrwinTheAnimalEnslaver.buy(Dog())

在这种情况下,您的选择是:

  1. 使用Retailer<out Pet>,这不允许像buy这样的调用成员“消费” T。您可以将其视为Retailer<any subtype of Pet>,不会有太大错误。还有一个双Retailer<in Pet>,它允许调用buy,但不能调用sell

  2. 声明interface Retailer<out T>不允许声明 buy,意思是“如果AB的子类型,则{{1 }}是Retailer<A>的子类型。