Получение класса списка с общим типом: List <Number>:: class
У меня есть типично типизированный класс Builder<T>
, который принимает аргумент конструктора Class<T>
, поэтому я могу сохранить тип вокруг. Это класс, который я использую много в Java-коде, поэтому я не хочу менять подпись.
Когда я пытаюсь использовать конструктор следующим образом:
Builder<List<Number>>(List<Number>::class)
Я получаю сообщение об ошибке: "В левой части литерала класса допускаются только классы"
Любой способ разрешить это?
Я не могу изменить конструктор для Builder
, слишком много классов java полагаются на него.
Я понимаю проблему стирания всего типа, я просто хочу сделать компилятор счастливым.
Ответы
Ответ 1
Из-за стирания типового типа List
класс имеет единственную реализацию для всех своих общих экземпляров. Вы можете получить только класс, соответствующий типу List<*>
, и тем самым создать только Builder<List<*>>
.
Этот экземпляр компоновщика подходит для создания списка чего-то. И снова из-за стирания типа, что это такое, вы можете решить самостоятельно с помощью непроверенных бросков:
Builder(List::class.java) as Builder<List<Number>>
Builder(List::class.java as Class<List<Number>>)
Другой подход заключается в создании встроенной вспомогательной функции reified:
inline fun <reified T : Any> Builder() = Builder(T::class.java)
и используйте его следующим образом:
Builder<List<Number>>()
Ответ 2
Решение состоит в том, чтобы использовать усовершенствованные дженерики в паре с токенами суперкласса.
Пожалуйста, обратитесь к этому вопросу для объяснения метода. Конструкторы в Kotlin не поддерживают reified generics, но вы можете использовать описанный там TypeReference
, чтобы написать фабричную функцию builder
, которая будет сохранять фактические общие параметры во время выполнения:
inline <reified T: Any> fun builder(): Builder<T> {
val type = object : TypeReference<T>() {}.type
return Builder(type)
}
Затем внутри Builder
вы можете проверить, является ли type
ParameterizedType
, и, если это так, type.actualTypeArguments
будет содержать фактические общие параметры.
Например, builder<List<Number>>()
сохранит информацию о Number
во время выполнения.
Ограничение этого подхода состоит в том, что вы не можете использовать неповрежденный обобщенный тип в качестве параметра усовершенствованного типа, поскольку тип должен быть известен во время компиляции.
Ответ 3
Если вы используете библиотеку gson уже в проекте (например, разбор json). Это обеспечивает класс для этого. com.google.gson.reflect.TypeToken()
. Так что вы можете использовать что-то вроде
Builder<List<Number>>(object : TypeToken<List<Number>>() {}.type::class)