---
title: "Generics em Kotlin: O que São e Como Funcionam | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/generics/"
markdown_url: "https://kotlin.dev.br/glossario/generics.MD"
description: "Entenda o que são Generics em Kotlin, como usar tipos genéricos em classes e funções para escrever código reutilizável."
date: "2026-02-14"
author: "Karina Melo"
---

# Generics em Kotlin: O que São e Como Funcionam | Kotlin Brasil

Entenda o que são Generics em Kotlin, como usar tipos genéricos em classes e funções para escrever código reutilizável.


## O que são Generics em Kotlin?

Generics permitem criar **classes, interfaces e funções que funcionam com qualquer tipo**, mantendo a segurança de tipos em tempo de compilação. Em vez de escrever código específico para `Int`, `String` ou qualquer outro tipo, você escreve uma vez e reutiliza com qualquer um deles.

### Classe genérica

```kotlin
class Caixa<T>(val conteudo: T) {
    fun abrir(): T {
        println("Abrindo a caixa...")
        return conteudo
    }
}

fun main() {
    val caixaDeTexto = Caixa("Presente surpresa")
    val caixaDeNumero = Caixa(42)

    println(caixaDeTexto.abrir()) // Presente surpresa
    println(caixaDeNumero.abrir()) // 42
}
```

O `T` é um parâmetro de tipo — pode ser qualquer coisa. O compilador garante que você não misture os tipos.

### Função genérica

```kotlin
fun <T> trocar(par: Pair<T, T>): Pair<T, T> {
    return Pair(par.second, par.first)
}

fun main() {
    val original = Pair("Kotlin", "Java")
    val trocado = trocar(original)
    println(trocado) // (Java, Kotlin)
}
```

### Restrições de tipo

Você pode restringir quais tipos são aceitos usando `where` ou `:`:

```kotlin
fun <T : Comparable<T>> maior(a: T, b: T): T {
    return if (a > b) a else b
}

fun main() {
    println(maior(10, 20))         // 20
    println(maior("Kotlin", "Java")) // Kotlin
}
```

Quando precisa de múltiplas restrições, use a cláusula `where`:

```kotlin
fun <T> processar(item: T) where T : Comparable<T>, T : CharSequence {
    println("Tamanho: ${item.length}, Valor: $item")
}

fun main() {
    processar("Kotlin") // Tamanho: 6, Valor: Kotlin
    // processar(42) // Erro: Int nao implementa CharSequence
}
```

### Variância: `in` e `out`

Kotlin tem um sistema de variância mais explícito que Java:

```kotlin
// out = produtor (covariant) — só retorna T
interface Fonte<out T> {
    fun obter(): T
}

// in = consumidor (contravariant) — só recebe T
interface Destino<in T> {
    fun enviar(item: T)
}

class FonteDeString : Fonte<String> {
    override fun obter() = "Kotlin Brasil"
}

fun main() {
    val fonte: Fonte<Any> = FonteDeString() // Funciona por causa do out
    println(fonte.obter())
}
```

- `out T` significa que `T` só aparece como retorno (posição de saída)
- `in T` significa que `T` só aparece como parâmetro (posição de entrada)

### Projeção de tipo (star projection)

Quando você não se importa com o tipo genérico, use `*`:

```kotlin
fun imprimirItens(lista: List<*>) {
    lista.forEach { println(it) }
}
```

### Reified type parameters

Em Kotlin, os tipos genéricos são apagados em tempo de execução (type erasure). Porém, com funções `inline` e o modificador `reified`, você pode acessar o tipo genérico em runtime:

```kotlin
inline fun <reified T> verificarTipo(valor: Any): Boolean {
    return valor is T
}

fun main() {
    println(verificarTipo<String>("Kotlin")) // true
    println(verificarTipo<Int>("Kotlin"))    // false
}
```

Isso é muito usado em frameworks para deserialização, injeção de dependência e navegação entre telas no Android.

### Generics em interfaces e herança

Generics se combinam naturalmente com interfaces para criar contratos flexíveis:

```kotlin
interface Repositorio<T> {
    fun buscarPorId(id: Int): T?
    fun salvar(item: T)
    fun listarTodos(): List<T>
}

data class Produto(val id: Int, val nome: String, val preco: Double)

class ProdutoRepositorio : Repositorio<Produto> {
    private val itens = mutableListOf<Produto>()

    override fun buscarPorId(id: Int) = itens.find { it.id == id }
    override fun salvar(item: Produto) { itens.add(item) }
    override fun listarTodos() = itens.toList()
}

fun main() {
    val repo = ProdutoRepositorio()
    repo.salvar(Produto(1, "Notebook", 3500.0))
    repo.salvar(Produto(2, "Mouse", 89.90))
    println(repo.listarTodos())
}
```

### Casos de Uso no Mundo Real

- **Repositórios genéricos**: criar uma interface `Repositorio<T>` que define operações CRUD e implementar para cada entidade do sistema, eliminando duplicação de código de acesso a dados.
- **Respostas de API padronizadas**: usar uma classe `ApiResponse<T>` que encapsula sucesso, erro e loading, permitindo que qualquer endpoint retorne o mesmo formato independente do tipo de dado.
- **Adapters no Android**: `RecyclerView.Adapter<VH>` usa generics para tipar o ViewHolder, e você pode criar adapters genéricos que funcionam com diferentes tipos de itens de lista.
- **Injeção de dependência**: frameworks como Koin e Hilt usam `reified` type parameters para resolver dependências pelo tipo sem precisar passar a classe como parâmetro explícito.

### Boas Práticas

- Use nomes de parâmetros de tipo descritivos quando o contexto exigir: `T` para tipo genérico, `K` e `V` para chave e valor, `E` para elementos de coleção, `R` para tipo de retorno.
- Prefira `out` em interfaces que apenas produzem valores e `in` em interfaces que apenas consomem. Isso torna a API mais flexível para os consumidores.
- Utilize restrições de tipo (`T : AlgumaInterface`) sempre que possível para evitar casts desnecessários e manter a segurança de tipos.
- Combine `inline` com `reified` quando precisar acessar o tipo genérico em runtime, em vez de passar `KClass<T>` como parâmetro.
- Evite star projection (`*`) quando você pode ser mais específico sobre o tipo, pois `*` limita as operações disponíveis.

### Erros Comuns

- **Tentar fazer `is T` sem `reified`**: devido ao type erasure, verificar o tipo genérico em runtime exige que a função seja `inline` e o parâmetro de tipo seja `reified`.
- **Confundir `in` e `out`**: usar `out` quando o tipo aparece em posição de entrada (parâmetro) causa erro de compilação. Lembre: `out` = saída (retorno), `in` = entrada (parâmetro).
- **Criar hierarquias genéricas excessivamente complexas**: aninhar múltiplos parâmetros de tipo como `Classe<A<B<C>>>` dificulta a leitura. Simplifique com typealias ou quebre em interfaces menores.
- **Esquecer que `List<Any>` não é supertipo de `List<String>` sem variância**: em Kotlin, `List` já é declarada como `List<out E>`, então funciona. Mas para suas próprias classes, você precisa declarar a variância explicitamente.
- **Usar casts genéricos não verificados**: `lista as List<String>` gera um warning de unchecked cast porque o tipo genérico é apagado em runtime. Use `filterIsInstance<String>()` quando possível.

### Perguntas Frequentes

**Qual a diferença entre generics em Kotlin e em Java?** Kotlin usa `in` e `out` para variância no local de declaração (declaration-site variance), enquanto Java usa wildcards `? extends` e `? super` no local de uso (use-site variance). Kotlin também suporta `reified` type parameters, que não existem em Java.

**O que é type erasure e como afeta generics?** Type erasure significa que os tipos genéricos são apagados em tempo de execução. Um `List<String>` e um `List<Int>` são indistinguíveis na JVM. O modificador `reified` em funções `inline` é a solução do Kotlin para contornar essa limitação.

**Posso ter múltiplos parâmetros de tipo?** Sim. Você pode declarar quantos precisar: `class Mapa<K, V>`, `fun <A, B> converter(valor: A, transformador: (A) -> B): B`. Cada parâmetro pode ter suas próprias restrições.

**Quando devo usar star projection?** Use `*` quando você precisa trabalhar com um tipo genérico mas não se importa com o parâmetro de tipo específico, como em funções que apenas imprimem ou verificam se uma coleção está vazia.

### Termos Relacionados

- [Interface](/glossario/interface) — contratos que frequentemente utilizam generics para definir APIs flexíveis
- [Inline](/glossario/inline) — modificador necessário para usar `reified` type parameters
- [Fun](/glossario/fun) — funções genéricas são declaradas com `fun` seguido de parâmetros de tipo
- [Lambda](/glossario/lambda) — frequentemente usada com funções genéricas como `map<T, R>`

Generics são essenciais para escrever código reutilizável e type-safe. A biblioteca padrão do Kotlin usa generics em praticamente tudo: listas, maps, flows e muito mais.
