Métodos estáticos em Kotlin: como um desenvolvedor Java não se perder no mundo de object e companion
\n\nSe você programa em Java e está começando a aprender Kotlin, certamente já se perguntou: "Onde está o static aqui?". Em Java, estamos acostumados a escrever public static void main() ou MathUtils.max() — é prático, simples e não requer criação de objeto. Mas em Kotlin, a palavra-chave static não existe. De forma alguma. Simplesmente não.
Não entre em pânico. Os desenvolvedores do Kotlin não enlouqueceram — eles apenas decidiram que métodos estáticos podem ser implementados de forma mais elegante, sem estado global e com uma arquitetura mais clara. Neste artigo, vamos abordar todas as formas de substituir o Java static em Kotlin: desde funções simples no nível de pacote até o poderoso companion object. Você aprenderá quando usar cada um e verá exemplos de código reais.
Vamos nessa! 🚀
\n\n\n\n
Por que não há static em Kotlin? (e isso é bom)
\n\nEm Java, static é, essencialmente, uma variável ou método global vinculado à classe, e não à instância. É útil para utilitários, mas viola os princípios de POO: membros estáticos não podem ser sobrescritos, são difíceis de testar e criam acoplamentos rígidos.
Kotlin incentiva uma abordagem mais limpa: funções e propriedades podem existir no nível de pacote (sem classe alguma!) ou ser organizadas em object-singletons. E se você precisar vincular um método à classe (como em Java), use companion object. Vamos analisar cada opção.
\n\n
Método 1: Funções de nível de pacote (o mais simples)
\n\nEm Kotlin, você pode declarar uma função ou propriedade diretamente em um arquivo, fora de uma classe. Isso é análogo a um método estático em Java, mas sem a camada extra de uma classe utilitária.
\n\nExemplo:
\n\n// Arquivo: MathUtils.kt\npackage com.example.utils\n\nfun max(a: Int, b: Int): Int {\n return if (a > b) a else b\n}\n\nval PI = 3.14159 // constante de nível de pacote\n\nAgora, esta função pode ser chamada de qualquer lugar (após a importação):
\n\nimport com.example.utils.max\nimport com.example.utils.PI\n\nfun main() {\n println(max(10, 20)) // 20\n println(PI) // 3.14159\n}\n\nQuando usar: para funções utilitárias simples e constantes que não exigem agrupamento em uma classe. Esta é a maneira mais fácil de obter um comportamento "estático".
\n\n\n\n
Método 2: Object-singleton (para um grupo de funções relacionadas)
\n\nSe você precisa agrupar vários métodos estáticos juntos (como MathUtils em Java), use object. É um singleton — uma única instância que é criada automaticamente no primeiro acesso.
Exemplo:
\n\nobject StringUtils {\n fun isEmpty(str: String?): Boolean {\n return str.isNullOrEmpty()\n }\n\n fun capitalizeFirst(str: String): String {\n return str.replaceFirstChar { it.uppercase() }\n }\n\n const val EMPTY_STRING = ""\n}\n\nUso:
\n\nfun main() {\n println(StringUtils.isEmpty(null)) // true\n println(StringUtils.capitalizeFirst("kotlin")) // Kotlin\n println(StringUtils.EMPTY_STRING) // ""\n}\n\nImportante: object é uma classe completa. Ela pode implementar interfaces, ter inicializadores e até herdar de outras classes. Mas não pode ter construtores (exceto privado).
\n\n
Método 3: Companion object (para métodos vinculados à classe)
\n\nEsta é a analogia mais próxima do Java static dentro de uma classe. companion object é um objeto companheiro que vive dentro da classe. Seus métodos e propriedades são chamados através do nome da classe, como estáticos.
Exemplo:
\n\nclass User(val name: String, val age: Int) {\n compan