O que é Companion Object em Kotlin?

O companion object é um objeto especial declarado dentro de uma classe que funciona como o equivalente aos membros estáticos do Java. Com ele, você pode acessar propriedades e funções diretamente pelo nome da classe, sem precisar criar uma instância.

Kotlin não tem a palavra-chave static. Em vez disso, usa companion objects — uma abordagem mais flexível e orientada a objetos.

Sintaxe básica

class Configuracao {
    companion object {
        const val VERSAO = "2.1.0"
        val AMBIENTE = "producao"

        fun info(): String {
            return "Versão $VERSAO - Ambiente: $AMBIENTE"
        }
    }
}

fun main() {
    println(Configuracao.VERSAO)    // 2.1.0
    println(Configuracao.info())    // Versão 2.1.0 - Ambiente: producao
}

Repare que você acessa VERSAO e info() direto pela classe, sem instanciar nada.

Factory methods

Um dos usos mais comuns do companion object é para criar factory methods — funções que constroem objetos de formas alternativas:

data class Usuario(val nome: String, val email: String) {
    companion object {
        fun criarAdmin(nome: String): Usuario {
            return Usuario(nome, "$nome@admin.com.br")
        }

        fun criarConvidado(): Usuario {
            return Usuario("Convidado", "convidado@temp.com.br")
        }
    }
}

fun main() {
    val admin = Usuario.criarAdmin("karina")
    val guest = Usuario.criarConvidado()

    println(admin)  // Usuario(nome=karina, email=karina@admin.com.br)
    println(guest)  // Usuario(nome=Convidado, email=convidado@temp.com.br)
}

Companion object com nome e interface

O companion object pode ter um nome e até implementar interfaces:

interface Serializavel {
    fun fromJson(json: String): Any
}

class Produto(val nome: String) {
    companion object Fabrica : Serializavel {
        override fun fromJson(json: String): Produto {
            return Produto(json) // simplificado
        }
    }
}

Quando usar?

Use companion object para constantes, factory methods, e qualquer funcionalidade que pertença à classe como um todo e não a uma instância específica. É o jeito Kotlin de lidar com o que seria static em Java.