---
title: "Data Class em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/data-class/"
markdown_url: "https://kotlin.dev.br/glossario/data-class.MD"
description: "Saiba o que é Data Class em Kotlin, como funciona e por que ela simplifica a criação de classes que armazenam dados."
date: "2026-02-03"
author: "Karina Melo"
---

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

Saiba o que é Data Class em Kotlin, como funciona e por que ela simplifica a criação de classes que armazenam dados.


## O que é Data Class em Kotlin?

Uma `data class` em Kotlin é uma classe feita especialmente para **armazenar dados**. Quando você declara uma classe com o modificador `data`, o compilador gera automaticamente os métodos `equals()`, `hashCode()`, `toString()`, `copy()` e funções `componentN()` -- tudo de graça.

Em Java, você precisaria escrever tudo isso na mão (ou usar uma biblioteca). Em Kotlin, basta uma linha.

Pense na data class como um formulário padronizado. Quando você preenche um formulário no cartório, os campos já estão definidos (nome, CPF, endereço) e dois formulários com os mesmos dados preenchidos são considerados equivalentes, independente de serem folhas de papel diferentes. A data class funciona da mesma forma: dois objetos com os mesmos valores são considerados iguais.

### Sintaxe básica

```kotlin
data class Usuario(val nome: String, val email: String, val idade: Int)

fun main() {
    val user = Usuario("Mariana", "mari@email.com", 30)
    println(user) // Usuario(nome=Mariana, email=mari@email.com, idade=30)
}
```

Olha só: o `toString()` já vem formatado bonitinho, sem você fazer nada.

### Comparação automática

Com `data class`, a comparação entre objetos é feita pelo **conteúdo**, não pela referência:

```kotlin
val a = Usuario("Lucas", "lucas@email.com", 25)
val b = Usuario("Lucas", "lucas@email.com", 25)

println(a == b)  // true — mesmo conteúdo
println(a === b) // false — objetos diferentes na memoria
```

### A função `copy()`

Uma das funcionalidades mais práticas é o `copy()`, que cria uma cópia do objeto permitindo alterar apenas alguns campos:

```kotlin
val original = Usuario("Ana", "ana@email.com", 22)
val atualizado = original.copy(idade = 23)

println(atualizado) // Usuario(nome=Ana, email=ana@email.com, idade=23)
```

Isso é especialmente útil quando você trabalha com objetos [imutáveis](/glossario/immutable/) e precisa criar variações.

### Destructuring

As funções `componentN()` geradas permitem usar [destructuring](/glossario/destructuring/):

```kotlin
val (nome, email, idade) = Usuario("Pedro", "pedro@email.com", 35)
println("$nome ($email) - $idade anos")
```

### Regras importantes

- O construtor primário precisa ter **pelo menos um parâmetro**.
- Todos os parâmetros do construtor devem ser `val` ou `var`.
- Data classes não podem ser `abstract`, `open`, `sealed` ou `inner`.

Data classes são perfeitas pra representar entidades, respostas de API, configurações e qualquer estrutura que carregue dados no seu projeto Kotlin.

### Data class com propriedades fora do construtor

Propriedades declaradas no corpo da classe não participam de `equals()`, `hashCode()`, `toString()` e `copy()`. Isso é útil para campos computados ou auxiliares:

```kotlin
data class Produto(val nome: String, val preco: Double) {
    var desconto: Double = 0.0

    val precoFinal: Double
        get() = preco * (1 - desconto)
}

fun main() {
    val p1 = Produto("Notebook", 4500.0)
    val p2 = Produto("Notebook", 4500.0)
    p1.desconto = 0.10

    println(p1 == p2)          // true -- desconto nao participa do equals
    println(p1.precoFinal)     // 4050.0
    println(p2.precoFinal)     // 4500.0
}
```

### Data class como modelo de API

Um cenário muito comum é usar data classes para representar respostas de APIs, combinando com [serialização](/glossario/serialization/):

```kotlin
data class RespostaApi<T>(
    val sucesso: Boolean,
    val dados: T?,
    val mensagem: String,
    val timestamp: Long = System.currentTimeMillis()
)

data class Endereco(
    val rua: String,
    val cidade: String,
    val estado: String,
    val cep: String
)

fun main() {
    val endereco = Endereco("Rua das Flores", "São Paulo", "SP", "01001-000")
    val resposta = RespostaApi(
        sucesso = true,
        dados = endereco,
        mensagem = "Endereço encontrado"
    )

    println(resposta)
    // Acesso seguro aos dados
    resposta.dados?.let { println("Cidade: ${it.cidade}") }
}
```

### Data class em coleções

Data classes funcionam perfeitamente com [collections](/glossario/collections/) graças ao `hashCode()` e `equals()` gerados automaticamente:

```kotlin
data class Contato(val nome: String, val telefone: String)

fun main() {
    val agenda = mutableSetOf<Contato>()
    agenda.add(Contato("Ana", "11999990000"))
    agenda.add(Contato("Bruno", "11988880000"))
    agenda.add(Contato("Ana", "11999990000")) // duplicata ignorada pelo Set

    println(agenda.size) // 2

    val porLetra = agenda.groupBy { it.nome.first() }
    println(porLetra)
    // {A=[Contato(nome=Ana, telefone=11999990000)],
    //  B=[Contato(nome=Bruno, telefone=11988880000)]}
}
```

### Casos de Uso no Mundo Real

- **DTOs (Data Transfer Objects)**: representar dados que trafegam entre camadas da aplicação, como entre repositório e viewmodel.
- **Respostas de API**: modelar JSONs de APIs REST com campos tipados e valores padrão para campos opcionais.
- **Eventos de domínio**: representar eventos em arquiteturas orientadas a eventos, como `PedidoCriado(id, data, valor)`.
- **Chaves compostas em mapas**: data classes funcionam como chaves de [Map](/glossario/collections/) graças ao `hashCode()` consistente.
- **Estado de UI**: em aplicações Android com Jetpack Compose, data classes representam o estado da tela (como `UiState(loading, data, error)`).

### Boas Práticas

- **Prefira `val` sobre `var`** nos parâmetros do construtor. Data classes imutáveis são mais seguras em ambientes concorrentes e mais previsíveis.
- **Use `copy()` para criar variações** em vez de tornar propriedades mutáveis. Isso segue o princípio de [imutabilidade](/glossario/immutable/).
- **Coloque valores padrão nos parâmetros** para facilitar a criação de instâncias parciais e testes.
- **Não coloque lógica de negócio complexa** dentro de data classes. Elas devem ser contêineres de dados simples.
- **Use [sealed classes](/glossario/sealed-class/) quando precisar de hierarquia**: data classes não podem ser herdadas, mas podem ser subtipos de uma sealed class.

### Erros Comuns

- **Declarar propriedades mutáveis que afetam igualdade**: se você usa `var` no construtor, alterar um campo depois de adicionar o objeto a um `Set` ou como chave de um `Map` pode causar comportamento imprevisível, já que o `hashCode` muda.
- **Confundir propriedades do corpo com as do construtor**: propriedades declaradas fora do construtor primário não participam de `equals`, `hashCode`, `toString` nem `copy`. Isso é intencional, mas pode surpreender.
- **Criar data classes com muitos parâmetros**: se sua data class tem mais de 7-8 parâmetros, considere agrupar campos relacionados em data classes menores.
- **Esquecer que `copy()` faz cópia rasa**: o `copy()` não clona objetos aninhados. Se um campo é uma `MutableList`, a cópia e o original compartilham a mesma lista.

### Perguntas Frequentes

**Qual a diferença entre data class e class normal?**
A data class gera automaticamente `equals()`, `hashCode()`, `toString()`, `copy()` e funções `componentN()`. Uma classe normal não gera nada disso -- você precisaria implementar manualmente.

**Posso herdar de uma data class?**
Não diretamente. Data classes são implicitamente `final`. Se você precisa de hierarquia, use uma [sealed class](/glossario/sealed-class/) como classe pai e data classes como subtipos.

**Data class ou [value class](/glossario/value-class/), quando usar cada uma?**
Use data class para estruturas com múltiplos campos. Use value class para envolver um único valor com significado semântico (como `Email`, `Cpf`), já que value classes têm otimização de memória.

**O `copy()` faz cópia profunda?**
Não. O `copy()` faz cópia rasa (shallow copy). Propriedades que são objetos mutáveis (como listas mutáveis) serão compartilhadas entre o original e a cópia. Para cópia profunda, você precisa implementar manualmente.
