То, что 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
в комментариях.