J'essaie de comprendre le but du mot clé reified
, apparemment cela nous permet de faire une réflexion sur les génériques .
Cependant, lorsque je le laisse de côté, cela fonctionne aussi bien. Quelqu'un veut-il expliquer quand cela fait une différence réelle ?
reified
convient?_fun <T> myGenericFun(c: Class<T>)
_
Dans le corps d'une fonction générique telle que myGenericFun
, vous ne pouvez pas accéder au type T
car il est uniquement disponible au moment de la compilation mais effacé au moment de l'exécution. Par conséquent, si vous souhaitez utiliser le type générique en tant que classe normale dans le corps de la fonction, vous devez explicitement transmettre la classe en tant que paramètre , comme indiqué dans myGenericFun
.
Si vous créez une fonction inline
avec un reifié T
, le type de T
est accessible même à l'exécution et vous n'avez donc pas besoin de passer le _Class<T>
_ en plus. Vous pouvez utiliser T
comme s'il s'agissait d'une classe normale, par exemple. vous voudrez peut-être vérifier si une variable est une instance de T
, ce que vous pouvez facilement faire ensuite: _myVar is T
_.
Une telle fonction inline
avec reified
de type T
se présente comme suit:
_inline fun <reified T> myGenericFun()
_
reified
Vous pouvez uniquement utiliser reified
en combinaison avec une fonction inline
. Une telle fonction oblige le compilateur à copier le bytecode de la fonction à chaque endroit où la fonction est utilisée (la fonction est "en ligne"). Lorsque vous appelez une fonction en ligne de type réifié, le compilateur connaît le type utilisé en tant qu'argument de type et modifie le bytecode généré pour utiliser directement la classe correspondante. Par conséquent, des appels tels que _myVar is T
_ deviennent _myVar is String
_ (si l'argument de type était String
) dans le bytecode et au moment de l'exécution.
Voyons un exemple qui montre à quel point reified
peut être utile. Nous voulons créer une fonction d'extension pour String
appelée toKotlinObject
qui tente de convertir une chaîne JSON en un objet Kotlin brut avec un type spécifié par le type générique de la fonction T
. Nous pouvons utiliser com.fasterxml.jackson.module.kotlin
pour cela et la première approche est la suivante:
a) Première approche sans type réifié
_fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.Java)
}
_
La méthode readValue
prend un type qu’elle est supposée analyser le JsonObject
. Si nous essayons d'obtenir le Class
du paramètre de type T
, le compilateur se plaint: "Impossible d'utiliser 'T' comme paramètre de type réifié. Utilisez plutôt une classe."
b) Solution de contournement avec le paramètre explicite Class
_fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.Java)
}
_
En guise de solution de contournement, le Class
de T
peut être transformé en paramètre de méthode, qui sera ensuite utilisé comme argument de readValue
. Cela fonctionne et est un modèle commun dans le code générique Java. On peut l'appeler comme suit:
_data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
_
c) La méthode Kotlin: reified
L'utilisation d'une fonction inline
avec reified
est un paramètre de type T
qui permet d'implémenter la fonction différemment:
_inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.Java)
}
_
Il n’est pas nécessaire de prendre le Class
de T
de plus, T
peut être utilisé comme s’il s’agissait d’une classe ordinaire. Pour le client, le code ressemble à ceci:
_json.toKotlinObject<MyJsonType>()
_
Une fonction en ligne de type reified
est non appelable à partir de code Java .