Я пытаюсь понять цель reified
ключевого слова, по-видимому, оно позволяет нам размышлять о дженериках .
Однако, когда я оставляю это, это работает так же хорошо. Кто-нибудь хочет объяснить, когда это имеет значение ?
Я пытаюсь понять цель reified
ключевого слова, по-видимому, оно позволяет нам размышлять о дженериках .
Однако, когда я оставляю это, это работает так же хорошо. Кто-нибудь хочет объяснить, когда это имеет значение ?
Ответы:
reified
хорошо дляfun <T> myGenericFun(c: Class<T>)
В теле общей функции, такой как myGenericFun
, вы не можете получить доступ к типу, T
потому что он доступен только во время компиляции, но стирается во время выполнения. Поэтому, если вы хотите использовать универсальный тип в качестве обычного класса в теле функции, вам нужно явно передать класс в качестве параметра, как показано в myGenericFun
.
Если вы создаете inline
функцию с помощью reified, T
то к ее типу T
можно обращаться даже во время выполнения, и, таким образом, вам не нужно Class<T>
дополнительно передавать . Вы можете работать с T
как если бы это был обычный класс, например , вы можете захотеть , чтобы проверить , является ли переменная является экземпляром T
, который вы можете легко сделать , то: myVar is T
.
Такая inline
функция с reified
типом T
выглядит следующим образом:
inline fun <reified T> myGenericFun()
reified
работаетВы можете использовать только reified
в сочетании с inline
функцией . Такая функция заставляет компилятор копировать байт-код функции в каждое место, где используется функция (функция «встроена»). Когда вы вызываете встроенную функцию с типом reified, компилятор знает фактический тип, используемый в качестве аргумента типа, и модифицирует сгенерированный байт-код для непосредственного использования соответствующего класса. Поэтому вызовы like myVar is T
становятся myVar is String
(если аргумент типа был String
) в байт-коде и во время выполнения.
Давайте посмотрим на пример, который показывает, насколько полезным reified
может быть. Мы хотим создать функцию расширения для String
вызываемого, toKotlinObject
которая пытается преобразовать строку JSON в простой объект Kotlin с типом, указанным универсальным типом функции T
. Мы можем использовать com.fasterxml.jackson.module.kotlin
для этого, и первый подход заключается в следующем:
а) первый подход без ограниченного типа
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
readValue
Метод принимает тип , который он , как предполагается разобрать JsonObject
к. Если мы пытаемся получить Class
параметр типа T
, компилятор жалуется: «Невозможно использовать« T »в качестве параметра типа reified. Вместо этого используйте класс».
б) Обходной путь с явным Class
параметром
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Чтобы обойти эту проблему, то Class
из T
может быть сделан параметр метода, который затем используется в качестве аргумента readValue
. Это работает и является общим шаблоном в общем коде Java. Это можно назвать следующим образом:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
в) путь Котлина: reified
Использование inline
функции с reified
параметром типа T
позволяет реализовать функцию по-разному:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
Там нет необходимости брать Class
из T
дополнительно, T
может быть использован , как если бы это был обычный класс. Для клиента код выглядит так:
json.toKotlinObject<MyJsonType>()
Встроенная функция с reified
типом не вызывается из кода Java .
ПРОСТО
* reified - это разрешение на использование во время компиляции (для доступа к T внутри функции de)
например:
inline fun <reified T:Any> String.convertToObject(): T{
val gson = Gson()
return gson.fromJson(this,T::class.java)
}
используя как:
val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
println(user.name)