Kotlin仿制药异常

时间:2019-01-30 15:05:19

标签: android generics kotlin

好,所以我有三种界面类型。

  1. Movement<T : Animal>
  2. Animal,带有子接口CatDogHorse
  3. AnimalMovement

运动界面

interface  Movement<T : Animal> {
    fun moveAnimal(type:T)
}

动物界面

interface Animal {
    fun takeSteps()
    fun jump()
    fun hide()
}

interface Cat : Animal
interface Dog : Animal

动物运动

interface CatMovement : Movement<Cat>

然后我实现CatMovement接口

class CatMovementImpl : CatMovement {
    override fun moveAnimal(type: Cat) {
        TODO("not implemented")        
    }
}

问题

fun TestGenerics() {
    var catMovement : Movement<Cat> = CatMovementImpl() // this works
    var catMovement : Movement<Animal> = CatMovementImpl() // this doesn't?
}

我确定在Java中这两行都可以正常工作。但是,在Kotlin中,第二行无法执行。为什么会这样呢?动物是猫的基本类型,所以这应该行得通吗?

2 个答案:

答案 0 :(得分:2)

我不是Kotlin的专家,但这似乎很正常:

当这样声明时:

postProcessAfterInitialization

您可以编写代码:

BeanPostProcessors

但是如果这样分配它:

ImportAware

是允许的,这意味着您的#section1 { height: 131px; color: #fff; background-color: transparent; margin-top: 246px; } 应该可以移动狗吗?

答案 1 :(得分:1)

评论中moskito所说的是正确的。

  

我很确定这在Java中也不起作用。 Movement<Cat>是   不是Movement<Animal>的子类型,与列表不是的相同方式   List<Object>的子类型。您可能需要阅读此内容。

但是在Kotlin中,可以使用类型差异来实现。

fun TestGenerics() {
    var catMovement1: Movement<Cat> = CatMovementImpl()
    var catMovement2: Movement<out Animal> = CatMovementImpl() // works
}

您基本上告诉编译器“接受Movement<Animal>的所有实现或Movement<S>S为上限的实现Animal”。

但是,随后出现了问题。您不能调用

val cat: Cat = /* ... */
catMovement2.moveAnimal(cat) // error

为您提供错误

  

投影类型为Movement<out Animal>的项目禁止使用[...]。

因为T只能用作生产者(外部头寸),而不能用作消费者(内部头寸),就像这样(用于说明要点的功能):

val c: Cat = catMovement2.getAnimal() // works

当您在out声明中使用Movement时,此问题立即变得清楚:

interface Movement<out T : Animal> {
    fun moveAnimal(type: T) // error
}

这取决于您的用例,但也许您应该让Kotlin推断类型,即CatMovementImpl

var catMovement = CatMovementImpl()

信用额为EpicPandaForce的原因是已经建议在评论中使用out