Próbuję zrozumieć cel reified
słowa kluczowego, najwyraźniej pozwala nam to na refleksję na temat leków generycznych .
Jednak kiedy to pominę, działa równie dobrze. Czy ktoś chciałby wyjaśnić, kiedy to rzeczywiście robi różnicę ?
Próbuję zrozumieć cel reified
słowa kluczowego, najwyraźniej pozwala nam to na refleksję na temat leków generycznych .
Jednak kiedy to pominę, działa równie dobrze. Czy ktoś chciałby wyjaśnić, kiedy to rzeczywiście robi różnicę ?
Odpowiedzi:
reified
dobre dlafun <T> myGenericFun(c: Class<T>)
W treści funkcji ogólnej, takiej jak myGenericFun
, nie można uzyskać dostępu do typu, T
ponieważ jest on dostępny tylko w czasie kompilacji, ale jest usuwany w czasie wykonywania. Dlatego jeśli chcesz użyć typu ogólnego jako normalnej klasy w treści funkcji, musisz jawnie przekazać klasę jako parametr, jak pokazano w myGenericFun
.
Jeśli utworzysz inline
funkcję z reified T
, typ T
można uzyskać nawet w czasie wykonywania, a zatem nie musisz Class<T>
dodatkowo przekazywać . Można pracować z T
tak jakby to było normalne klasy, na przykład może chcesz sprawdzić, czy zmienna jest instancją T
, które można łatwo zrobić wtedy: myVar is T
.
Taka inline
funkcja z reified
typem T
wygląda następująco:
inline fun <reified T> myGenericFun()
reified
działaMożesz używać tylko reified
w połączeniu z inline
funkcją . Taka funkcja powoduje, że kompilator kopiuje kod bajtowy funkcji w każde miejsce, w którym funkcja jest używana (funkcja jest „wstawiana”). Kiedy wywołujesz funkcję wbudowaną z typem reified, kompilator zna rzeczywisty typ używany jako argument typu i modyfikuje wygenerowany kod bajtowy, aby bezpośrednio używał odpowiedniej klasy. Dlatego wywołania takie jak myVar is T
get myVar is String
(jeśli argument typu był String
) w kodzie bajtowym iw czasie wykonywania.
Spójrzmy na przykład, który pokazuje, jak pomocne reified
może być. Chcemy utworzyć funkcję rozszerzającą dla String
wywoływanej, toKotlinObject
która próbuje przekonwertować ciąg JSON na zwykły obiekt Kotlin o typie określonym przez typ ogólny funkcji T
. Możemy com.fasterxml.jackson.module.kotlin
do tego użyć, a pierwsze podejście jest następujące:
a) Pierwsze podejście bez typu zreifikowanego
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
readValue
Metoda zajmuje typ, który to ma do analizowania JsonObject
do. Jeśli spróbujemy pobrać Class
parametr typu T
, kompilator narzeka: „Nie można użyć 'T' jako parametru typu reified. Zamiast tego użyj klasy.”
b) Obejście z jawnym Class
parametrem
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Aby obejść ten problem, Class
of T
można ustawić jako parametr metody, który następnie zostanie użyty jako argument funkcji readValue
. To działa i jest częstym wzorcem w ogólnym kodzie Java. Można to nazwać w następujący sposób:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) Droga Kotlina: reified
Użycie inline
funkcji z reified
parametrem typu T
umożliwia inną implementację funkcji:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
Nie ma potrzeby brać dodatkowego Class
udziału T
, T
można z niej korzystać tak, jakby to była zwykła klasa. Dla klienta kod wygląda następująco:
json.toKotlinObject<MyJsonType>()
Funkcja wstawiana z reified
typem nie jest wywoływana z kodu Java .
PROSTY
* reified to udzielenie pozwolenia na użycie w czasie kompilacji (aby uzyskać dostęp do funkcji T inside de)
na przykład:
inline fun <reified T:Any> String.convertToObject(): T{
val gson = Gson()
return gson.fromJson(this,T::class.java)
}
używając takich jak:
val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
println(user.name)