Historia de la pregunta:
En la JVM, durante la ejecución, no hay información sobre los parámetros de tipo genérico (borrado de tipo). Kotlin propuso un mecanismo de parámetros genéricos reificados para funciones en línea, a fin de permitir el acceso a la información del tipo T durante la ejecución sin trucos como pasar Class<T>. Esta es una de las herramientas más poderosas del lenguaje Kotlin.
Problema:
Se requiere escribir una función que acepte un valor de tipo T (genérico) y, dependiendo del tipo del parámetro, realice diferentes acciones, sin pasar explícitamente java.lang.Class y sin reflexión en Java. El borrado de tipo clásico no permite conocer el tipo T durante la ejecución.
Solución:
En Kotlin, para funciones en línea, se permite declarar parámetros genéricos con el modificador reified, lo que permite "capturar" el tipo T dentro del cuerpo de la función, trabajar con él como un tipo normal, realizar comprobaciones de tipo y crear instancias a través de la reflexión.
Ejemplo de código:
inline fun <reified T> isOfType(value: Any): Boolean { return value is T } isOfType<String>(123) // false isOfType<Int>(123) // true
Características clave:
¿Se puede usar reified fuera de funciones en línea?
¡No! Solo las funciones en línea (y propiedades inline-lazy) pueden tener un parámetro genérico reificado. La razón es que se sustituye el código en el lugar de la llamada, solo así se puede "sustituir" un tipo específico por T.
Ejemplo de código:
// Error de compilación: fun <reified T> errorFun() { } // Variante correcta: inline fun <reified T> okFun() { }
¿Se puede obtener Class<T> dentro de una función reificada en línea?
¡Sí! Para ello, solo es necesario escribir T::class.java o T::class. Esto es muy conveniente para escribir fábricas genéricas, analizadores y trabajar con la API de reflexión.
Ejemplo de código:
inline fun <reified T> printType() { println(T::class.java) } printType<String>() // class java.lang.String
¿Se pueden crear instancias del tipo T a través del constructor en funciones reificadas?
Parcialmente. Se puede utilizar reflexión, pero no se puede hacer directamente new T() como en C++ o C#:
inline fun <reified T : Any> makeInstance(): T? { return T::class.constructors.firstOrNull()?.call() }
Pero este enfoque requiere que T tenga un constructor sin parámetros.
Función con reified que llama a una operación de reflexión pesada:
inline fun <reified T> foo(): T? = T::class.constructors.firstOrNull()?.call()
Ventajas:
Desventajas:
Uso de reified para una comprobación de tipo universal o safeCast:
inline fun <reified T> safeCast(value: Any?): T? = value as? T
Ventajas:
Desventajas: