Получение класса списка с общим типом: 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)