Contexte de la question :
Dans la JVM, au moment de l'exécution, il n'y a pas d'informations sur les paramètres de génération (type erasure). Kotlin a proposé un mécanisme de paramètres de type générique reified pour les fonctions en ligne, afin de réaliser l'accès à des informations de type T pendant l'exécution sans les contraintes de passer Class<T>. C'est l'un des outils les plus puissants du langage Kotlin.
Problème :
Il faut écrire une fonction qui prend une certaine valeur de type T (générique) et exécuter différentes actions en fonction du type du paramètre, sans passer explicitement java.lang.Class et sans utiliser la réflexion à la manière de Java. L'effritement classique des types ne permet pas de déterminer le type T pendant l'exécution.
Solution :
En Kotlin, il est possible de déclarer des paramètres génériques avec le modificateur reified pour les fonctions en ligne, ce qui permet "d'immobiliser" le type T à l'intérieur du corps de la fonction, de travailler avec lui comme avec un type normal, de réaliser des vérifications de type et de créer des instances via la réflexion.
Exemple de code :
inline fun <reified T> isOfType(value: Any): Boolean { return value is T } isOfType<String>(123) // false isOfType<Int>(123) // true
Caractéristiques clés :
Peut-on utiliser reified en dehors des fonctions en ligne ?
Non ! Seules les fonctions en ligne (et les propriétés en ligne paresseuses) peuvent avoir des paramètres génériques reified. La raison est que le code est substitué à l'endroit de l'appel, c'est la seule manière de "remplacer" un type concret à la place de T.
Exemple de code :
// Erreur de compilation : fun <reified T> errorFun() { } // Variante correcte : inline fun <reified T> okFun() { }
Peut-on obtenir Class<T> à l'intérieur d'une fonction reified en ligne ?
Oui ! Il suffit d'écrire T::class.java ou T::class. C'est extrêmement pratique pour écrire des fabriques génériques, des parseurs et travailler avec l'API de réflexion.
Exemple de code :
inline fun <reified T> printType() { println(T::class.java) } printType<String>() // class java.lang.String
Peut-on créer des instances de type T via un constructeur dans une fonction reified ?
Partiellement. Il est possible d'utiliser la réflexion, mais on ne peut pas faire directement new T() comme en C++ ou C# :
inline fun <reified T : Any> makeInstance(): T? { return T::class.constructors.firstOrNull()?.call() }
Mais cette approche nécessite que T possède un constructeur sans paramètres.
Fonction avec reified, appelant une opération de réflexion lourde dans le code :
inline fun <reified T> foo(): T? = T::class.constructors.firstOrNull()?.call()
Avantages :
Inconvénients :
Utilisation de reified pour une vérification de type universelle ou un safeCast :
inline fun <reified T> safeCast(value: Any?): T? = value as? T
Avantages :
Inconvénients :