companion object é um mecanismo da linguagem Kotlin que substitui a palavra-chave static do Java para declarar membros estáticos de uma classe. Kotlin não possui static nativo — em vez disso, usa-se uma declaração object com o modificador companion dentro de uma classe. De acordo com JetBrains, 2025, companion object permite chamar métodos e propriedades através do nome da classe, tornando-os equivalentes completos aos membros estáticos no ecossistema Java.
Pontos Principais
companion object é um tipo especial de object declaration em Kotlin marcado com a palavra-chave companion. Ele permite declarar membros que pertencem à classe em vez de suas instâncias — ou seja, membros estáticos em termos Java. Diferente do Java, onde static é um modificador para campos e métodos individuais, em Kotlin os membros estáticos são agrupados dentro de um único objeto companheiro.
Qualquer classe em Kotlin pode conter exatamente um companion object. Os membros deste objeto são acessíveis através do nome da classe sem criar uma instância: MyClass.method(). Em termos de bytecode, um companion object é compilado como uma classe interna separada, e seus métodos tornam-se métodos estáticos da classe externa ao usar a anotação @JvmStatic.
De acordo com o Google I/O 2024, companion object tornou-se o padrão principal para métodos fábrica, constantes e funções auxiliares em aplicativos Android modernos escritos em Kotlin. Os desenvolvedores o escolhem em vez de classes utilitárias com funções de nível de pacote porque companion object mantém uma conexão lógica com a classe proprietária.
Use companion object para agrupar contexto estático — constantes, fábricas, métodos auxiliares que pertencem logicamente à classe mas não requerem uma instância.
A sintaxe básica do companion object é simples: a palavra-chave companion é colocada antes da declaração object dentro da classe. Se nenhum nome for especificado, o objeto recebe o nome Companion, que pode ser acessado explícita ou implicitamente.
class User {
companion object {
const val TABLE_NAME = "users"
fun create(name: String): User {
return User(name)
}
}
val name: String
constructor(name: String) { this.name = name }
}
// Access via class name
val table = User.TABLE_NAME
val user = User.create("Alice")
No exemplo acima, TABLE_NAME e create() são acessíveis via User.TABLE_NAME e User.create(). Observe o modificador const para constantes primitivas — ele garante a inserção do valor em tempo de compilação, similar ao Java static final para primitivos e String.
Se um companion object não tem nome, pode ser acessado através do nome automático Companion: User.Companion.TABLE_NAME. Na prática isso raramente é necessário, mas é útil ao chamar código Java ou ao usar reflexão.
// Both calls are equivalent
User.create("Bob")
User.Companion.create("Bob")
// Getting reference to companion object
val companion: User.Companion = User
Um companion object pode ter um nome, o que melhora a legibilidade do código e permite acessá-lo por um nome significativo. Factory é o nome mais comum para um companion object usado como fábrica.
class HttpResponse {
companion object Factory {
fun ok(body: String): HttpResponse = HttpResponse(200, body)
fun notFound(): HttpResponse = HttpResponse(404, "Not Found")
fun serverError(): HttpResponse = HttpResponse(500, "Internal Error")
}
}
// Access via Factory name
val response = HttpResponse.Factory.ok("data")
Um companion object nomeado ajuda a documentar o propósito dos membros estáticos. Em refatoração, o nome torna o código autodocumentável — o desenvolvedor vê instantaneamente que Factory cria instâncias de HttpResponse.
Uma classe pode conter apenas um companion object. Esta é uma diferença fundamental do Java, onde você pode declarar qualquer número de campos e métodos estáticos sem agrupamento. Se precisar de múltiplos grupos lógicos de membros estáticos, use declarações object aninhadas sem companion.
De acordo com a documentação oficial do Kotlin (Kotlin Docs, 2025), a limitação de um companion object é motivada pelo design da linguagem: membros estáticos devem estar fortemente acoplados à classe, e um objeto companheiro fornece um limite claro para essa conexão. Se houver muitos membros estáticos, é um sinal para refatorar a classe.
Em Kotlin, as interfaces também podem conter um companion object. Isso permite definir métodos estáticos e constantes diretamente dentro de uma interface, algo impossível em Java. Esta abordagem é frequentemente usada para declarar constantes relacionadas à interface ou métodos fábrica.
interface ApiService {
companion object {
const val BASE_URL = "https://api.example.com"
const val TIMEOUT_MS = 5000
fun create(client: OkHttpClient): ApiService =
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.build()
.create(ApiService::class.java)
}
}
Neste exemplo, BASE_URL, TIMEOUT_MS e create() pertencem à interface ApiService, não às suas implementações. Isso é conveniente: todas as constantes e a lógica de fábrica para criar uma instância do serviço API estão localizadas em um só lugar — dentro da própria interface.
As implementações da interface não herdam os membros do companion object — eles são chamados apenas através do nome da interface: ApiService.BASE_URL.
Ao chamar métodos de companion object do código Java, por padrão eles são acessíveis como métodos da classe interna Companion, não como métodos estáticos da classe externa. Para exportá-los como métodos e campos estáticos reais para Java, use a anotação @JvmStatic para métodos e @JvmField para campos.
| Anotação | Aplicação | Resultado em Java |
|---|---|---|
| @JvmStatic | Métodos de companion object | Método estático: ClassName.method() |
| @JvmField | Campos de companion object | Campo estático: ClassName.field |
| const | Primitivos e String | Constante inline: o compilador substitui o valor |
| sem anotação | Métodos/campos por padrão | Companion.method() / Companion.field |
class MathUtils {
companion object {
const val PI = 3.14159
@JvmStatic
fun square(x: Int): Int = x * x
@JvmField
val TAG: String = "MathUtils"
}
}
// Called in Java as MathUtils.square(5), MathUtils.TAG
Recomenda-se usar @JvmStatic para todos os métodos públicos de companion object que devem ser acessíveis a partir de código Java. const aplica-se apenas a tipos primitivos e String — para outros tipos use @JvmField.
Em projetos reais, companion object é usado para vários cenários padrão. Métodos fábrica são o padrão mais comum: em vez de múltiplos construtores com assinaturas diferentes, usam-se métodos fábrica nomeados no companion object.
sealed class NetworkResult<out T> {
data class Success<out T>(val data: T) : NetworkResult<T>()
data class Error(val message: String) : NetworkResult<Nothing>()
companion object {
fun loading<T>(): NetworkResult<T> =
Loading()
}
}
private class Loading<T> : NetworkResult<T>()
companion object em NetworkResult fornece um método fábrica loading() que cria uma instância Loading com o tipo genérico correto. Sem este método, você teria que criar uma instância diretamente via Loading(), o que expõe a implementação interna.
companion object é frequentemente usado para armazenar constantes específicas da classe. Constantes declaradas com const val são inseridas em tempo de compilação, proporcionando zero overhead em tempo de execução.
class UserRepository {
companion object {
private const val TAG = "UserRepository"
private const val CACHE_SIZE = 100
private const val DEFAULT_PAGE_SIZE = 20
}
}
Perguntas Frequentes
Um object normal é um singleton completo que existe independentemente da classe. companion object é um object dentro de uma classe cujos membros são chamados através do nome da classe externa. Em bytecode, um companion object torna-se uma classe aninhada estática, enquanto um object normal torna-se uma classe singleton autônoma.
Não, companion object não é herdado por subclasses. Se a classe B estende a classe A, então B.method() não chamará o método do companion object da classe A — você precisa chamar A.method(). Isso corresponde ao comportamento dos métodos estáticos em Java.
Por padrão — através de ClassName.Companion.method(). Para chamá-lo como método estático, adicione @JvmStatic ao método do companion object. Para campos, use @JvmField ou declare-os com const val para primitivos.
Os desenvolvedores do Kotlin decidiram abandonar static em favor do companion object para um trabalho uniforme com objetos. static em Java viola princípios de POO porque métodos estáticos não estão vinculados a uma instância. companion object é um objeto de primeira classe que pode ser passado, estendido com funções de extensão e implementar interfaces.
Ao usar const val para primitivos e String — zero overhead, o valor é inserido no bytecode. Para métodos, não há overhead a menos que o método seja inline. Na maioria dos casos, companion object não cria nenhum impacto mensurável no desempenho. Use @JvmStatic apenas para API pública chamada a partir de Java.
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