---
title: "Boxing em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/boxing/"
markdown_url: "https://kotlin.dev.br/glossario/boxing.MD"
description: "Entenda o que é boxing e unboxing em Kotlin, como tipos primitivos são encapsulados em objetos é o impacto na performance."
date: "2025-08-02"
author: "Karina Melo"
---

# Boxing em Kotlin: O que É e Como Funciona | Kotlin Brasil

Entenda o que é boxing e unboxing em Kotlin, como tipos primitivos são encapsulados em objetos é o impacto na performance.


## O que é Boxing em Kotlin?

**Boxing** é o processo de encapsular um tipo primitivo (como `Int`, `Long`, `Double`) dentro de um objeto wrapper correspondente (como `java.lang.Integer`, `java.lang.Long`, `java.lang.Double`). O processo inverso, extrair o valor primitivo do objeto, é chamado de **unboxing**.

Em Kotlin, diferente do Java, você não declara explicitamente `int` vs `Integer`. Tudo e `Int`. Porem, o compilador decide por baixo dos panos se vai usar o tipo primitivo (`int`) ou o wrapper (`Integer`) dependendo do contexto. Entender quando o boxing acontece e fundamental para escrever código performatico.

### Como o compilador decide?

O Kotlin compila tipos como `Int` para primitivos JVM (`int`) sempre que possível. Porem, em certas situacoes, o boxing é obrigatório:

- Quando o tipo e **nullable** (`Int?`), o valor precisa ser boxed porque primitivos não podem ser `null`.
- Quando o tipo é usado como **argumento generico** (`List<Int>`), pois generics na JVM trabalham com objetos.
- Quando o tipo é usado em contextos que exigem **referência de objeto**.

```kotlin
val a: Int = 42       // Compilado como primitivo int
val b: Int? = 42      // Compilado como Integer (boxed)
val lista: List<Int> = listOf(1, 2, 3) // Cada Int e boxed como Integer
```

### Impacto na performance

O boxing tem custo. Cada vez que um primitivo e boxed, um novo objeto e alocado no heap. Em loops intensivos ou coleções grandes, isso pode gerar pressao significativa no garbage collector.

```kotlin
// Versão com boxing: cada iteracao cria um objeto Integer
fun somaBoxed(lista: List<Int>): Int {
    var soma = 0
    for (valor in lista) {
        soma += valor // unboxing acontece aqui
    }
    return soma
}

// Versão sem boxing: usa IntArray com primitivos
fun somaPrimitiva(array: IntArray): Int {
    var soma = 0
    for (valor in array) {
        soma += valor // nenhum boxing
    }
    return soma
}
```

A segunda versão e significativamente mais rápida para arrays grandes porque não envolve alocacao de objetos nem garbage collection adicional.

### Arrays especializados

Para evitar boxing em arrays, Kotlin oferece tipos especializados:

```kotlin
val intArray: IntArray = intArrayOf(1, 2, 3)          // int[] na JVM
val longArray: LongArray = longArrayOf(1L, 2L, 3L)    // long[] na JVM
val doubleArray: DoubleArray = doubleArrayOf(1.0, 2.0) // double[] na JVM

// Comparando com Array<Int> que sofre boxing
val boxedArray: Array<Int> = arrayOf(1, 2, 3) // Integer[] na JVM
```

Sempre prefira `IntArray`, `LongArray`, `DoubleArray` e similares quando performance for importante.

### Identidade vs igualdade com boxing

Um detalhe sutil e que o boxing pode afetar a identidade de objetos:

```kotlin
val a: Int = 127
val boxedA: Int? = a
val outroBoxedA: Int? = a
println(boxedA === outroBoxedA) // true (cache de -128 a 127)

val b: Int = 128
val boxedB: Int? = b
val outroBoxedB: Int? = b
println(boxedB === outroBoxedB) // false (fora do cache)
println(boxedB == outroBoxedB)  // true (igualdade estrutural)
```

A JVM faz cache de `Integer` para valores entre -128 e 127. Fora dessa faixa, cada boxing cria um novo objeto, entao a comparação de identidade (`===`) retorna `false`. Sempre use `==` para comparar valores numericos.

### Boxing em funções genericas

Funções genericas sempre causam boxing porque a JVM não suporta generics com primitivos:

```kotlin
fun <T> imprimir(valor: T) {
    println(valor)
}

fun main() {
    imprimir(42) // 42 e boxed para Integer antes de ser passado
}
```

Para evitar isso em casos específicos, você pode usar funções `inline` com `reified`:

```kotlin
inline fun <reified T> verificarTipo(valor: T): String {
    return when (T::class) {
        Int::class -> "Inteiro"
        String::class -> "String"
        else -> "Outro"
    }
}
```

Porem, isso não elimina completamente o boxing em todos os cenários. Para performance crítica, considere sobrecarregar a função com versões específicas para cada tipo primitivo.

### Quando usar tipos que causam boxing

O boxing não e algo que você precisa evitar obsessivamente. Na maioria dos casos, o impacto e negligenciavel. Preocupe-se com boxing apenas quando:

- Você esta processando **milhoes de elementos** em loops apertados.
- Você esta trabalhando com **coleções muito grandes** onde a alocacao de memória importa.
- Profiling mostrou que **garbage collection** esta sendo um gargalo no seu sistema.
- Você esta desenvolvendo **bibliotecas de alta performance** ou algoritmos numericos.

Para código de aplicação comum, como chamadas de API, manipulação de UI ou lógica de negocios, o boxing e perfeitamente aceitavel e não merece otimização prematura.

### Casos de Uso no Mundo Real

1. **Processamento de dados em larga escala**: em pipelines de ETL e processamento batch que manipulam milhoes de registros numericos, evitar boxing ao usar `IntArray` e `DoubleArray` em vez de `List<Int>` e `List<Double>` pode reduzir o consumo de memória pela metade e acelerar o processamento significativamente, além de diminuir a pressao no garbage collector.

2. **Motores de jogos e simulacoes**: em game loops que executam calculos de fisica, colisao e renderizacao dezenas de vezes por segundo, operações com tipos primitivos sem boxing sao essenciais. Cada frame pode envolver milhares de calculos com coordenadas e vetores, e a alocacao de objetos wrapper nesse contexto causa stuttering perceptivel ao usuário.

3. **aplicações Android com listas grandes**: ao exibir listas com milhares de itens em RecyclerView ou LazyColumn, coleções de IDs ou indices como `IntArray` em vez de `List<Int>` reduzem a alocacao de memória e diminuem o risco de janks na interface, especialmente em dispositivos com hardware mais limitado.

4. **Bibliotecas de machine learning e estatistica**: bibliotecas que realizam operações matriciais, calculos estatisticos ou treinamento de modelos precisam operar sobre arrays densos de primitivos. O boxing nessas situacoes não e apenas uma questao de performance, mas também de viabilidade, já que a diferenca de consumo de memória pode tornar o processamento impraticavel.

### Boas Praticas

- Use `IntArray`, `LongArray`, `DoubleArray` e demais arrays especializados em vez de `Array<Int>`, `Array<Long>` ou `Array<Double>` sempre que estiver trabalhando com colecoes numericas onde performance importa.
- Evite declarar variaveis como nullable (`Int?`, `Double?`) quando o valor nunca sera `null`. Tipos nullable forcam boxing na JVM, gerando alocacao desnecessaria de objetos.
- Sempre compare valores numericos com `==` (igualdade estrutural) e nunca com `===` (identidade referencial). O boxing pode criar objetos diferentes para o mesmo valor numerico, fazendo `===` retornar `false` de forma inesperada.
- Ao criar funções utilitarias que operam sobre tipos numericos e precisam de alta performance, considere fornecer sobrecargas especificas para cada tipo primitivo em vez de depender exclusivamente de generics, que sempre causam boxing.
- Utilize ferramentas de profiling como o Android Profiler ou o JMH (Java Microbenchmark Harness) para medir o impacto real do boxing antes de otimizar. otimização prematura reduz legibilidade sem beneficio mensuravel.

### Perguntas Frequentes

**P: Como saber se o meu código esta sofrendo boxing desnecessário?**
R: Voce pode inspecionar o bytecode gerado pelo Kotlin usando a opção "Show Kotlin Bytecode" no IntelliJ IDEA e clicar em "Decompile". Procure por chamadas a `Integer.valueOf()`, `Long.valueOf()` e similares, que indicam boxing. Alem disso, ferramentas de profiling como o JMH e o Android Profiler ajudam a medir o impacto real em tempo de execução.

**P: Value classes (`@JvmInline value class`) eliminam o boxing?**
R: Em muitos cenários sim. Uma value class que encapsula um tipo primitivo e representada como o primitivo em tempo de execução, sem alocacao de objeto adicional. Porem, o boxing ainda acontece quando a value class e usada como tipo nullable, em colecoes genericas ou em contextos que exigem referência de objeto, seguindo as mesmas regras de qualquer tipo primitivo.

**P: Existe diferenca de performance entre `listOf(1, 2, 3)` e `intArrayOf(1, 2, 3)`?**
R: Sim. `listOf(1, 2, 3)` cria uma `List<Int>` onde cada elemento e boxed como `java.lang.Integer`, resultando em tres alocacoes de objetos além da própria lista. `intArrayOf(1, 2, 3)` cria um `int[]` nativo da JVM sem nenhum boxing. Para listas pequenas a diferenca e negligenciavel, mas em colecoes com milhares de elementos o impacto na memória e no garbage collector se torna relevante.

**P: Kotlin Multiplatform lida com boxing da mesma forma que a JVM?**
R: Nao. O boxing e um conceito específico da JVM, onde generics só trabalham com objetos. Em plataformas nativas (Kotlin/Native), não existe essa distincao entre primitivos e objetos wrapper. Em Kotlin/JS, os números sao mapeados para o tipo `number` do JavaScript. Portanto, preocupacoes com boxing sao mais relevantes ao direcionar a JVM ou o Android.

### Erros comuns

1. **Comparar tipos nullable com `===`**: como vimos, boxing pode criar objetos diferentes para o mesmo valor. Sempre use `==` para comparações de valor.

2. **Ignorar arrays especializados**: usar `Array<Int>` em vez de `IntArray` quando performance importa. A diferenca pode ser significativa em coleções grandes.

3. **Otimizar prematuramente**: evitar `List<Int>` em favor de `IntArray` em todo lugar, mesmo quando a lista e pequena e a legibilidade do código e mais importante.

4. **Esquecer que nullable causa boxing**: declarar `var contador: Int? = 0` quando o valor nunca sera null. Use `Int` sem interrogacao sempre que possível.

5. **Nao considerar o boxing em benchmarks**: ao comparar performance de diferentes abordagens, o boxing pode distorcer resultados se não for levado em conta.

### Coleções sem boxing

Para cenários de alta performance, existem bibliotecas que oferecem coleções especializadas sem boxing, como a biblioteca `eclipse-collections` ou implementacoes customizadas com `IntArray` como backing store:

```kotlin
class ListaDeInteiros {
    private var dados = IntArray(16)
    private var tamanho = 0

    fun adicionar(valor: Int) {
        if (tamanho == dados.size) {
            dados = dados.copyOf(dados.size * 2)
        }
        dados[tamanho++] = valor
    }

    fun obter(indice: Int): Int = dados[indice]

    fun tamanho(): Int = tamanho
}
```

### Termos relacionados

- **Value Class**: permite criar tipos que encapsulam um primitivo sem overhead de boxing adicional em tempo de execução.
- **Inline**: funções inline podem ajudar a reduzir boxing em certos contextos com lambdas.
- **Reified**: permite acessar o tipo generico em tempo de execução em funções inline, evitando algumas formas de boxing.
- **Nullable**: tipos nullable (`Int?`) sempre causam boxing porque primitivos não podem ser null na JVM.
- **IntArray/LongArray/DoubleArray**: arrays especializados que evitam boxing, armazenando primitivos diretamente.

Compreender boxing e unboxing e essencial para escrever Kotlin que seja ao mesmo tempo idiomatico e eficiente. Na maioria dos casos, confie no compilador. Nos casos onde performance e crítica, use as ferramentas que o Kotlin oferece para manter tudo no mundo dos primitivos.
