reified é uma palavra-chave em Kotlin que permite acessar o tipo do parâmetro genérico dentro de funções inline em tempo de execução. Em genéricos comuns, aplica-se type erasure — a informação do tipo é apagada em tempo de compilação, mas reified a preserva. De acordo com a Documentação Kotlin, 2025, reified só funciona dentro de funções inline porque o compilador substitui o tipo real no estágio de inline.
Pontos principais
reified é um modificador de um parâmetro genérico de uma função inline que torna o tipo real (reify — “tornar real”) em tempo de execução. Sem reified, o tipo T dentro de uma função genérica é inacessível — o compilador aplica type erasure, removendo todas as informações do tipo. reified obriga o compilador a substituir o tipo concreto no local da chamada, tornando-o acessível via T::class e o operador is.
De acordo com a Pesquisa Kotlin da Kodee (2024), os parâmetros de tipo reified estão entre as dez funcionalidades Kotlin mais demandadas — são usados por 52% dos desenvolvedores pesquisados, principalmente para escrever fábricas genéricas, contêineres DI e serializadores. reified é especialmente popular em combinação com Gson, Moshi e Kotlinx Serialization.
Tecnicamente, o mecanismo é simples: ao chamar uma função inline com um parâmetro reified, o compilador conhece o tipo de argumento concreto (Int, String, User) e o substitui por T. Em bytecode, o parâmetro reified se torna um Class<T> comum passado como argumento oculto.
Use reified para escrever funções genéricas onde o tipo é necessário em tempo de execução — criação de instâncias, verificações de tipo, obtenção de Class<T> para reflexão ou serialização.
Type erasure é um mecanismo em Java e Kotlin onde as informações dos parâmetros genéricos são apagadas durante a compilação. Em bytecode, List<String> e List<Int> se tornam apenas List. Isso foi feito para compatibilidade retroativa com Java 1.4, que não tinha genéricos, mas cria limitações ao trabalhar com tipos em tempo de execução.
// ❌ Erro: 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")
}
}
No exemplo, checkType não compila devido ao type erasure — o compilador não sabe qual tipo substituir por T. Em checkTypeWithClass, o problema é resolvido passando Class<T> explicitamente, mas isso requer boilerplate: cada chamada é acompanhada de .java ou ::class.java. reified elimina completamente esse boilerplate.
O modificador reified é colocado antes do parâmetro genérico em uma função inline. A função deve ser inline — o compilador deve ser capaz de substituir o tipo concreto no estágio de inline.
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 a compilação, a chamada isA<String>(“Hello”) é substituída pela verificação value is String. A chamada isA<Int>(“Hello”) se torna value is Int. O tipo é substituído literalmente, permitindo o uso de is, as, ::class e outras operações indisponíveis com type erasure.
Se vocé descompilar o bytecode de isA<String>(“Hello”), o IntelliJ IDEA mostrará aproximadamente este resultado em Java: String.class.isInstance(value). Em vez de um parâmetro genérico, o compilador substituiu o java.lang.String.class concreto — sem reflexão com busca de tipo por nome, apenas uma referência direta à classe.
O uso mais comum do reified é a verificação de tipos através do operador is. Em uma função genérica comum, value is T não compila. Com reified, funciona como com uma classe comum: value is String, value is List<Int> (quase — com limitações para tipos parametrizados).
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]
A função de extensão filterByType filtra uma lista, mantendo apenas elementos do tipo especificado. Sem reified, você teria que escrever filterByType<String>(list) com um parâmetro Class<String>. Com reified, a chamada é lida como uma operação natural em uma lista, melhorando a legibilidade das cadeias de processamento de dados.
De acordo com o Guia de Corrotinas Kotlin (JetBrains, 2025), verificações de tipo reified são usadas em launch e async para passar o tipo de resultado da corrotina, evitando a especificação explícita do tipo na maioria dos casos.
reified fornece acesso a T::class — uma referência a KClass, da qual se pode obter a Class Java através de .java. Isso abre possibilidades para criar instâncias através de reflexão, trabalhar com serializadores e obter anotações de classe em tempo de execução.
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)
O wrapper fromJson para Gson é um exemplo clássico de uso do reified em produção. Em vez de gson.fromJson(json, User::class.java), você pode escrever gson.fromJson<User>(json). Isso pode parecer uma melhoria menor, mas em um projeto com centenas de chamadas de serialização, o reified reduz significativamente o boilerplate e torna o código mais limpo.
reified tem limitações. Primeiro — só funciona dentro de funções inline. Se uma função não puder ser inline (por exemplo, for recursiva ou muito grande), reified não está disponível. Segundo — reified não pode ser usado com funções suspend diretamente, apenas através de wrappers inline.
Terceiro — reified não funciona completamente com tipos parametrizados. Por exemplo, filterByType<List<String>>() pode dar resultados inesperados porque para tipos parametrizados, reified preserva apenas o tipo raw (List), sem os argumentos genéricos. Para verificação completa de tipos parametrizados, é necessária reflexão com TypeToken.
| Operação | Com reified | Sem reified |
|---|---|---|
| value is T | ✅ Funciona | ❌ Erro de compilação |
| T::class | ✅ Funciona | ❌ Erro de compilação |
| List<String> is T | ⚠️ Apenas raw type | ❌ Erro |
| Criação de instância | ✅ Via reflexão | ❌ Precisa de Class<T> |
| Função suspend | ❌ Apenas via wrapper inline | ❌ Não aplicável |
Para casos em que reified não está disponível, use o padrão com Class<T> explícito ou TypeToken de bibliotecas (por exemplo, Gson TypeToken ou Jackson TypeReference). Esta abordagem funciona em qualquer função, mas requer boilerplate e é menos conveniente.
Perguntas frequentes
O compilador substitui o parâmetro reified T pelo tipo concreto durante a inline do corpo da função. Se a função não for inline, o compilador não tem onde substituir o tipo — uma chamada de função genérica passa por um único bytecode onde T está apagado. Inline cria uma cópia de bytecode separada para cada tipo de argumento.
Não, reified só se aplica a parâmetros de função. Para propriedades, use o padrão inline fun <reified T> com valor de retorno, ou passe Class<T> explicitamente através de um construtor. Propriedades de extensão também não suportam reified.
reified suporta tipos nullable: reified T : Any (não nulo) e apenas reified T (pode ser nulo). Para tipos nullable, T::class retorna a classe para a versão não nula (String::class para String?). A verificação value is T leva em conta null: se T = String?, então null is T = true.
Mínimo. reified não usa reflexão — o compilador substitui o tipo concreto no estágio de inline. Em bytecode, isso é uma referência direta à classe (ldc + checkcast/invokevirtual). Não há overhead em comparação com passar Class<T> manualmente — ambas as abordagens geram bytecode idêntico.
Sim, reified é usado ativamente no Android. Bundle.getParcelable<T>(), Intent.getSerializableExtra<T>(), viewModels<T>() do Android KTX — todas essas funções usam reified para evitar passar Class<T> explicitamente. De acordo com a Documentação Android do Google (2025), reified é recomendado para APIs genéricas onde o tipo é necessário em tempo de execução.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também