Что такое Java-эквивалент ковариантных и контравариантных модификаторов Kotlin?

Рассмотрим следующий интерфейс Kotlin:

interface Box<out T : SomeType> {
    val item: T
}

Реализация этого с помощью Kotlin будет выглядеть примерно так:

data class BoxImpl<out T : SomeType>(override val item: T) : Box<T>

Теперь я хочу преобразовать этот интерфейс в Java:

public interface Box<T extends SomeType> {
    T getItem();
}

Но реализация этого в Kotlin вызывает проблему:

data class BoxImpl<out T : SomeType>(private val item: T) : Box<T> {

    override fun getItem(): T {
        return item
    }
}

Проблема в том, что компилятор Kotlin жалуется, что T инвариантен для интерфейса Java, но ковариантен для реализации.

Итак, как указать out (ковариантную) дисперсию в Java?

Кроме того, как бы вы указали in (контравариантную) дисперсию?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Java не поддерживает вариантность сайта объявления, как это делает Kotlin. Он поддерживает только вариант использования сайта. Другими словами, вариантность может использоваться только для типов переменных и параметров, а не в определениях классов/интерфейсов.

Таким образом, в Java вы бы указали свой интерфейс и определения классов без отклонений, и каждый раз, когда вам нужно изменение, вы должны были бы объявлять переменную вместе с ним.

Ковариация использует ? extends, а контравариантность использует ? super, например:

Box<? extends Number> numberBox = new BoxImpl(1);
Ответ принят как подходящий

В Java нет вариации сайта объявления, как в Kotlin. То есть вы не можете указать дисперсию типа при его объявлении. Однако у него есть дисперсия по месту использования — вы можете указать дисперсию при использовании типа, например, как тип переменной.

Например,

// Kotlin
var foo: SomeGenericType<out T>
var bar: SomeGenericType<in T>

похож на:

// Java
SomeGenericType<? extends T> foo;
SomeGenericType<? super T> bar;

(Мнемоника для этого PECS.)

Однако принципиальное отличие состоит в том, что вы можете передавать nulls в методы переменной Java bar,

bar.someMethod(null);

Но в Котлин нельзя ничего передать bar — он буквально принимает Nothing!

Если вы пытаетесь использовать универсальный тип из Java в своем коде Kotlin, я думаю, вам придется сделать это @UnsafeVariance, чтобы подавить ошибку компилятора на данный момент.

// Of course, only do this if you are sure that Box is covariant!
data class BoxImpl<out T : SomeType>(private val item: T) : Box<@UnsafeVariance T>

Также ведутся дискуссии о добавлении возможности аннотировать параметры типа Java, чтобы компилятор Kotlin знал об их дисперсии. Смотрите это и это. Надеюсь, мы сможем получить это когда-нибудь в будущем. Хотя это не меняет того факта, что в Java нет различий между сайтами объявлений.

Другие вопросы по теме