TL; DR: Ce qui est reifiedbon pour
fun <T> myGenericFun(c: Class<T>)
Dans le corps d'une fonction générique comme myGenericFun, vous ne pouvez pas accéder au type Tcar 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 transmettre explicitement la classe en tant que paramètre, comme indiqué dans myGenericFun.
Si vous créez une inlinefonction avec un reified T , le type de Tpeut être consulté même au moment de l'exécution et vous n'avez donc pas besoin de passer le Class<T>. Vous pouvez travailler avec Tcomme si elle était une classe normale, par exemple , vous pouvez vérifier si une variable est une instance de T , que vous pouvez facilement faire alors: myVar is T.
Une telle inlinefonction avec reifiedtype Tressemble à ceci:
inline fun <reified T> myGenericFun()
Comment reifiedfonctionne
Vous ne pouvez utiliser reifiedqu'en combinaison avec une inlinefonction . 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 avec un type réifié, le compilateur connaît le type réel utilisé comme argument de type et modifie le bytecode généré pour utiliser directement la classe correspondante. Par conséquent, les appels comme myVar is Tdeviennent myVar is String(si l'argument type l'était String) dans le bytecode et à l'exécution.
Exemple
Jetons un coup d'œil à un exemple qui montre à quel point cela reifiedpeut être utile . Nous voulons créer une fonction d'extension pour Stringcalled toKotlinObjectqui tente de convertir une chaîne JSON en un objet Kotlin simple avec un type spécifié par le type générique de la fonction T. Nous pouvons utiliser com.fasterxml.jackson.module.kotlinpour 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 readValueméthode prend un type qu'elle est censée analyser le JsonObjectto. Si nous essayons d'obtenir le Classparamètre de type T, le compilateur se plaint: "Impossible d'utiliser 'T' comme paramètre de type réifié. Utilisez une classe à la place."
b) Solution de contournement avec un Classparamètre explicite
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Pour contourner le problème, vous pouvez faire de Classof Tun paramètre de méthode, qui sera ensuite utilisé comme argument de readValue. Cela fonctionne et est un modèle courant dans le code Java générique. Il peut être appelé comme suit:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) La voie Kotlin: reified
L'utilisation d'une inlinefonction avec reifiedparamètre de type Tpermet 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 Classde en Tplus, Tpeut être utilisé comme s'il s'agissait d'une classe ordinaire. Pour le client, le code ressemble à ceci:
json.toKotlinObject<MyJsonType>()
Remarque importante: utilisation de Java
Une fonction inline avec reifiedtype ne peut pas être appelée à partir du code Java .