Reified en Kotlin — qué es, sintaxis y uso

Autor: IT Sectr Publicado: 2026-06-21 Tiempo de lectura: 8 min

reified es una palabra clave en Kotlin que permite acceder al tipo del parámetro genérico dentro de funciones inline en tiempo de ejecución. En los genéricos normales se aplica type erasure — la información del tipo se borra en tiempo de compilación, pero reified la conserva. Según la Documentación de Kotlin, 2025, reified solo funciona dentro de funciones inline porque el compilador sustituye el tipo real en la etapa de incrustación.

Puntos clave

  • reified — un modificador de parámetro genérico que conserva la información del tipo en tiempo de ejecución
  • Solo inline — reified funciona exclusivamente dentro de funciones inline
  • Type erasure — el mecanismo estándar de Java/Kotlin que borra los tipos genéricos; reified lo evita
  • Comprobaciones is — posibles: if (value is T) en lugar de if (value is String)
  • Creación de instancias — T::class.java.newInstance() sin pasar Class<T>

¿Qué es reified en Kotlin?

reified es un modificador de un parámetro genérico de una función inline que hace que el tipo sea real (reify — “hacer real”) en tiempo de ejecución. Sin reified, el tipo T dentro de una función genérica es inaccesible — el compilador aplica type erasure, eliminando toda la información del tipo. reified obliga al compilador a sustituir el tipo concreto en el lugar de la llamada, haciéndolo accesible a través de T::class y el operador is.

Según la Encuesta de Kotlin de Kodee (2024), los parámetros de tipo reified se encuentran entre las diez características de Kotlin más demandadas — los utiliza el 52% de los desarrolladores encuestados, principalmente para escribir fábricas genéricas, contenedores DI y serializadores. reified es especialmente popular en combinación con Gson, Moshi y Kotlinx Serialization.

Técnicamente, el mecanismo es simple: al llamar a una función inline con un parámetro reified, el compilador conoce el tipo de argumento concreto (Int, String, User) y lo sustituye por T. En bytecode, el parámetro reified se convierte en un Class<T> normal que se pasa como argumento oculto.

Use reified para escribir funciones genéricas donde se necesite el tipo en tiempo de ejecución — creación de instancias, comprobaciones de tipo, obtención de Class<T> para reflexión o serialización.

El problema del type erasure en genéricos

Type erasure es un mecanismo en Java y Kotlin donde la información de los parámetros genéricos se borra durante la compilación. En bytecode, List<String> y List<Int> se convierten simplemente en List. Esto se hizo para mantener la compatibilidad hacia atrás con Java 1.4, que no tenía genéricos, pero crea limitaciones al trabajar con tipos en tiempo de ejecución.

kotlin
// ❌ Error: Cannot check for instance of erased type
fun <T> checkType(value: Any) {
    if (value is T) { // type erasure — T is unknown
        println("Type matches")
    }
}

// ✅ Solution: pass Class as parameter
fun <T> checkTypeWithClass(
    value: Any,
    clazz: Class<T>
) {
    if (clazz.isInstance(value)) {
        println("Type matches")
    }
}

En el ejemplo, checkType no se compila debido al type erasure — el compilador no sabe qué tipo sustituir por T. En checkTypeWithClass, el problema se resuelve pasando explícitamente Class<T>, pero esto requiere código boilerplate: cada llamada va acompañada de .java o ::class.java. reified elimina por completo este boilerplate.

Sintaxis de reified y cómo funciona

El modificador reified se coloca antes del parámetro genérico en una función inline. La función debe ser inline — el compilador debe poder sustituir el tipo concreto en la etapa de incrustación.

kotlin
inline fun <reified T> isA(value: Any): Boolean {
    return value is T
}

fun main() {
    println(isA<String>("Hello")) // true
    println(isA<Int>("Hello"))  // false
}

Durante la compilación, la llamada isA<String>(“Hello”) se reemplaza por la comprobación value is String. La llamada isA<Int>(“Hello”) se convierte en value is Int. El tipo se sustituye literalmente, lo que permite usar is, as, ::class y otras operaciones no disponibles con type erasure.

Descompilación de una función reified

Si descompila el bytecode de isA<String>(“Hello”), IntelliJ IDEA mostrará aproximadamente este resultado en Java: String.class.isInstance(value). En lugar de un parámetro genérico, el compilador sustituyó el java.lang.String.class concreto — sin reflexión con búsqueda de tipo por nombre, solo una referencia directa a la clase.

Comprobaciones de tipo con reified: is y as

El uso más común de reified es la comprobación de tipos mediante el operador is. En una función genérica normal, value is T no se compila. Con reified, funciona igual que con una clase normal: value is String, value is List<Int> (casi — con limitaciones para tipos parametrizados).

kotlin
inline fun <reified T> List<Any>.filterByType(): List<T> {
    return this.filter { it is T }.map { it as T }
}

val mixed = listOf("a", 1, "b", 2)
val strings = mixed.filterByType<String>() // ["a", "b"]
val ints = mixed.filterByType<Int>()    // [1, 2]

La función de extensión filterByType filtra una lista, conservando solo los elementos del tipo especificado. Sin reified, habría que escribir filterByType<String>(list) con un parámetro Class<String>. Con reified, la llamada se lee como una operación natural sobre una lista, mejorando la legibilidad de las cadenas de procesamiento de datos.

Según la Guía de Corrutinas de Kotlin (JetBrains, 2025), las comprobaciones de tipo reified se utilizan en launch y async para pasar el tipo de resultado de la corrutina, evitando la especificación explícita del tipo en la mayoría de los casos.

Reflexión con reified: crear instancias y acceder a Class

reified proporciona acceso a T::class — una referencia a KClass, desde la que se puede obtener la Class de Java a través de .java. Esto abre posibilidades para crear instancias mediante reflexión, trabajar con serializadores y obtener anotaciones de clase en tiempo de ejecución.

kotlin
inline fun <reified T> createInstance(): T =
    T::class.java.getDeclaredConstructor().newInstance()

// Usage
data class User(val name: String = "default")
val user = createInstance<User>()

// Serialization with Gson
inline fun <reified T> Gson.fromJson(json: String): T =
    this.fromJson(json, T::class.java)

// Getting annotations
inline fun <reified T> hasAnnotation<A>(): Boolean where A : Annotation =
    T::class.java.isAnnotationPresent(A::class.java)

El envoltorio fromJson para Gson es un ejemplo clásico del uso de reified en producción. En lugar de gson.fromJson(json, User::class.java), se puede escribir gson.fromJson<User>(json). Esto puede parecer una mejora menor, pero en un proyecto con cientos de llamadas de serialización, reified reduce significativamente el boilerplate y hace que el código sea más limpio.

Limitaciones de reified y alternativas

reified tiene limitaciones. Primero — solo funciona dentro de funciones inline. Si una función no puede hacerse inline (por ejemplo, es recursiva o demasiado grande), reified no está disponible. Segundo — reified no se puede usar con funciones suspend directamente, solo a través de envoltorios inline.

Tercero — reified no funciona completamente con tipos parametrizados. Por ejemplo, filterByType<List<String>>() puede dar resultados inesperados porque para tipos parametrizados, reified solo conserva el tipo raw (List), sin los argumentos genéricos. Para la comprobación completa de tipos parametrizados, se requiere reflexión con TypeToken.

OperaciónCon reifiedSin reified
value is T✅ Funciona❌ Error de compilación
T::class✅ Funciona❌ Error de compilación
List<String> is T⚠️ Solo raw type❌ Error
Creación de instancia✅ Mediante reflexión❌ Necesita Class<T>
Función suspend❌ Solo mediante envoltorio inline❌ No aplicable

Para los casos en los que reified no esté disponible, use el patrón con Class<T> explícito o TypeToken de bibliotecas (por ejemplo, Gson TypeToken o Jackson TypeReference). Este enfoque funciona en cualquier función, pero requiere boilerplate y es menos cómodo.

Preguntas frecuentes

¿Por qué reified solo funciona con funciones inline?

El compilador reemplaza el parámetro reified T por el tipo concreto durante la incrustación del cuerpo de la función. Si la función no es inline, el compilador no tiene dónde sustituir el tipo — una llamada a una función genérica pasa por un único bytecode donde T está borrado. Inline crea una copia de bytecode separada para cada tipo de argumento.

¿Se puede declarar una propiedad reified?

No, reified solo se aplica a parámetros de función. Para propiedades, use el patrón inline fun <reified T> con un valor de retorno, o pase explícitamente Class<T> a través de un constructor. Las propiedades de extensión tampoco admiten reified.

¿Cómo funciona reified con tipos nullable?

reified admite tipos nullable: reified T : Any (no nulo) y simplemente reified T (puede ser nulo). Para tipos nullable, T::class devuelve la clase para la versión no nula (String::class para String?). La comprobación value is T tiene en cuenta el null: si T = String?, entonces null is T = true.

¿Hay overhead con reified?

Mínimo. reified no usa reflexión — el compilador sustituye el tipo concreto en la etapa de incrustación. En bytecode, esto es una referencia directa a la clase (ldc + checkcast/invokevirtual). No hay overhead en comparación con pasar Class<T> manualmente — ambos enfoques generan bytecode idéntico.

¿Se puede usar reified en desarrollo Android?

, reified se usa activamente en Android. Bundle.getParcelable<T>(), Intent.getSerializableExtra<T>(), viewModels<T>() de Android KTX — todas estas funciones usan reified para evitar pasar explícitamente Class<T>. Según los Documentos de Android de Google (2025), reified se recomienda para API genéricas donde se necesita el tipo en tiempo de ejecución.

Resumen

  • reified — un modificador de parámetro genérico para funciones inline que conserva el tipo en tiempo de ejecución
  • Type erasure — el mecanismo estándar de borrado de tipos; reified lo evita mediante la incrustación
  • is/as — las comprobaciones y conversiones de tipo funcionan con reified como con clases normales
  • Referencia de clase — T::class y T::class.java están disponibles para reflexión y serialización
  • Solo inline — reified es imposible sin una función inline debido al mecanismo de sustitución de tipo
  • Tipos parametrizados — reified no conserva los argumentos genéricos (solo raw type)
  • Aplicaciones — serialización Gson/Moshi, contenedores DI, comprobaciones de tipo en colecciones, Android KTX

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también