TL; DR
Компилятор Kotlin выдает здесь ошибку (несоответствие типов):
fun <T: A()> getUtil(t: T): Util<T> = if (t is B) UtilB() else // ...
С сигнатурой класса B
: class B : A()
, класс Util
равен class Util<T: A>
, а класс UtilB
равен class UtilB: Util<B>()
.
Компилятор Kotlin выдает предупреждение (непроверенное приведение) здесь:
fun <T: A()> getUtil(t: T): Util<T> = if (t is B) UtilB() as Util<T> else // ...
Насколько я понимаю Kotlin smart cast должен знать, что UtilB() as Util<T>
проверяется t is B
.
Java Код и компилятор дают точно такой же результат.
Насколько я знаю, что это должно быть ограничение на Java генериков. Как я могу это исправить?
Описание проблемы
У меня есть следующие настройки, где абстрактный класс имеет несколько реализаций и класс util, который обеспечивает одинаковые функциональные возможности для каждого из эти реализации.
Чтобы быть в безопасности типов, я решил создать абстрактный класс Util<T: A>
и для каждого производного класса A
другой UtilB: Util<B>
класс.
Чтобы получить правильное использование класс для каждой реализации, я создал функцию для сопутствующего объекта getUtil
, которая возвращает правильный класс утилит для каждой реализации на основе параметра универсального c типа T, который расширяет A: T: A
, таким образом, возвращая тип Util<T>
.
Однако, когда я написал тело функции для каждого производного класса A
, проверив тип параметра с помощью is B
, а затем вернул правильное значение util с помощью UtilB()
, компилятор Kotlin дал мне ошибку в точке возврата, говоря, что UtilB
не относится к типу Util<T>
, хотя это должно быть.
Затем я произнесла UtilB
Util<B>
и это сработало, но дало мне ошибку "Unchecked cast". В соответствии с моим пониманием Kotlin умное приведение должно быть в состоянии выяснить, что оно действительно является проверенным приведением (проверено с помощью is B
), и после выполнения быстрого теста оно также оказалось действительным ...
Я переписал тот же код в Java с точно такими же результатами ...
Насколько я знаю, это ограничение дженериков Java / Kotlin. Я хотел бы знать, как я могу проверить этот актерский состав. Это вообще возможно?
Код
Вот минимальный рабочий (или не работающий) пример:
abstract class A
class B : A()
class C : A()
abstract class Util<T : A> {
abstract fun getName(): String
companion object {
fun <T : A> getUtil(t: T): Util<T> = when(t) {
is B -> UtilB() as Util<T> // warning
is C -> UtilC() // this event gives an error
else -> throw IllegalArgumentException("No util for this class.")
}
}
}
class UtilB : Util<B>() {
override fun getName(): String = "B"
}
class UtilC : Util<C>() {
override fun getName(): String = "C"
}
fun main() {
val b = B()
val c = C()
val utilB = Util.getUtil(b)
val utilC = Util.getUtil(c)
println(utilB.getName()) // prints B
println(utilC.getName()) // prints C
}