Companion object en Kotlin: qué es, sintaxis y uso

Autor: IT Sectr Publicado: 2026-06-21 Tiempo de lectura: 9 min

companion object es un mecanismo del lenguaje Kotlin que reemplaza la palabra clave static de Java para declarar miembros estáticos de una clase. Kotlin no tiene static incorporado — en su lugar, se usa una declaración object con el modificador companion dentro de una clase. Según JetBrains, 2025, companion object permite llamar métodos y propiedades a través del nombre de la clase, siendo el equivalente completo de los miembros estáticos en el ecosistema Java.

Puntos Clave

  • companion object es una declaración object dentro de una clase con la palabra clave companion, reemplazando Java static
  • Miembros estáticos accesibles a través del nombre de la clase sin crear una instancia: ClassName.method()
  • Companion object con nombre permite asignar un nombre al objeto para un código más legible
  • Interfaces en Kotlin también pueden contener companion object con implementación de métodos
  • @JvmStatic — anotación para exportar métodos de companion object como métodos static reales en Java

¿Qué es companion object en Kotlin?

companion object es un tipo especial de object declaration en Kotlin que se marca con la palabra clave companion. Permite declarar miembros que pertenecen a la clase en lugar de a sus instancias — es decir, miembros estáticos en términos de Java. A diferencia de Java, donde static es un modificador para campos y métodos individuales, en Kotlin los miembros estáticos se agrupan dentro de un único objeto compañero.

Cualquier clase en Kotlin puede contener exactamente un companion object. Los miembros de este objeto son accesibles a través del nombre de la clase sin crear una instancia: MyClass.method(). En términos de bytecode, un companion object se compila como una clase interna separada, y sus métodos se convierten en métodos estáticos de la clase externa al usar la anotación @JvmStatic.

Según Google I/O 2024, companion object se ha convertido en el patrón principal para métodos fábrica, constantes y funciones auxiliares en aplicaciones Android modernas escritas en Kotlin. Los desarrolladores lo eligen sobre las clases utilitarias con funciones a nivel de paquete porque companion object mantiene una conexión lógica con la clase propietaria.

Utiliza companion object para agrupar contexto estático — constantes, fábricas, métodos auxiliares que pertenecen lógicamente a la clase pero no requieren una instancia.

Sintaxis de companion object: declaración y acceso

La sintaxis básica de companion object es simple: la palabra clave companion se coloca antes de la declaración object dentro de la clase. Si no se especifica un nombre, el objeto recibe el nombre Companion, al que se puede acceder explícita o implícitamente.

kotlin
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")

En el ejemplo anterior, TABLE_NAME y create() son accesibles mediante User.TABLE_NAME y User.create(). Observa el modificador const para constantes primitivas — garantiza la inserción del valor en tiempo de compilación, similar a Java static final para primitivos y String.

Acceso implícito y explícito mediante Companion

Si un companion object no tiene nombre, se puede acceder a él mediante el nombre automático Companion: User.Companion.TABLE_NAME. En la práctica esto rara vez es necesario, pero es útil al llamar desde código Java o al usar reflexión.

kotlin
// Both calls are equivalent
User.create("Bob")
User.Companion.create("Bob")

// Getting reference to companion object
val companion: User.Companion = User

Companion object con nombre y características

Un companion object puede tener un nombre, lo que mejora la legibilidad del código y permite acceder a él mediante un nombre significativo. Factory es el nombre más común para un companion object utilizado como fábrica.

kotlin
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")

Un companion object con nombre ayuda a documentar el propósito de los miembros estáticos. En refactorización, el nombre hace que el código se autodocumente — el desarrollador ve instantáneamente que Factory crea instancias de HttpResponse.

Limitación: exactamente un companion object por clase

Una clase puede contener solo un companion object. Esta es una diferencia fundamental con Java, donde se puede declarar cualquier cantidad de campos y métodos estáticos sin agrupar. Si se necesitan múltiples grupos lógicos de miembros estáticos, se usan declaraciones object anidadas sin companion.

Según la documentación oficial de Kotlin (Kotlin Docs, 2025), la limitación de un solo companion object está motivada por el diseño del lenguaje: los miembros estáticos deben estar estrechamente acoplados con la clase, y un objeto compañero proporciona un límite claro para esta conexión. Si hay demasiados miembros estáticos, es una señal para refactorizar la clase.

Companion object en interfaces

En Kotlin, las interfaces también pueden contener un companion object. Esto permite definir métodos estáticos y constantes directamente dentro de una interfaz, algo que no es posible en Java. Este enfoque se utiliza a menudo para declarar constantes relacionadas con la interfaz o métodos fábrica.

kotlin
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)
    }
}

En este ejemplo, BASE_URL, TIMEOUT_MS y create() pertenecen a la interfaz ApiService, no a sus implementaciones. Esto es conveniente: todas las constantes y la lógica de fábrica para crear una instancia del servicio API están ubicadas en un solo lugar — dentro de la propia interfaz.

Las implementaciones de la interfaz no heredan los miembros del companion object — se llaman solo a través del nombre de la interfaz: ApiService.BASE_URL.

@JvmStatic y @JvmField: compatibilidad con Java

Al llamar a métodos de companion object desde código Java, por defecto son accesibles como métodos de la clase interna Companion, no como métodos estáticos de la clase externa. Para exportarlos como métodos y campos estáticos reales para Java, usa la anotación @JvmStatic para métodos y @JvmField para campos.

AnotaciónAplicaciónResultado en Java
@JvmStaticMétodos de companion objectMétodo estático: ClassName.method()
@JvmFieldCampos de companion objectCampo estático: ClassName.field
constPrimitivos y StringConstante inline: el compilador sustituye el valor
sin anotaciónMétodos/campos por defectoCompanion.method() / Companion.field
kotlin
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

Se recomienda usar @JvmStatic para todos los métodos públicos de companion object que deban ser accesibles desde código Java. const se aplica solo a tipos primitivos y String — para otros tipos usa @JvmField.

Ejemplos prácticos de uso de companion object

En proyectos reales, companion object se utiliza para varios escenarios estándar. Métodos fábrica es el patrón más común: en lugar de múltiples constructores con diferentes firmas, se usan métodos fábrica con nombre en companion object.

kotlin
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 en NetworkResult proporciona un método fábrica loading() que crea una instancia Loading con el tipo genérico correcto. Sin este método, tendrías que crear una instancia directamente mediante Loading(), lo que expone la implementación interna.

Constantes y etiquetas de logging

companion object se usa a menudo para almacenar constantes específicas de la clase. Las constantes declaradas con const val se insertan en tiempo de compilación, proporcionando cero sobrecarga en tiempo de ejecución.

kotlin
class UserRepository {
    companion object {
        private const val TAG = "UserRepository"
        private const val CACHE_SIZE = 100
        private const val DEFAULT_PAGE_SIZE = 20
    }
}

Preguntas Frecuentes

¿En qué se diferencia companion object de un object normal en Kotlin?

Un object normal es un singleton completo que existe independientemente de la clase. companion object es un object dentro de una clase cuyos miembros se llaman a través del nombre de la clase externa. En bytecode, un companion object se convierte en una clase anidada estática, mientras que un object normal se convierte en una clase singleton autónoma.

¿Se puede heredar companion object?

No, companion object no se hereda por subclases. Si la clase B extiende la clase A, entonces B.method() no llamará al método del companion object de la clase A — debes llamar a A.method(). Esto coincide con el comportamiento de los métodos estáticos en Java.

¿Cómo llamar a companion object desde código Java?

Por defecto — mediante ClassName.Companion.method(). Para llamarlo como método estático, añade @JvmStatic al método del companion object. Para campos, usa @JvmField o decláralos con const val para primitivos.

¿Por qué no hay palabra clave static en Kotlin?

Los desarrolladores de Kotlin decidieron abandonar static en favor de companion object para un trabajo uniforme con objetos. static en Java viola los principios de POO porque los métodos estáticos no están vinculados a una instancia. companion object es un objeto de primera clase que se puede pasar, extender con funciones de extensión e implementar interfaces.

¿Afecta companion object al rendimiento?

Al usar const val para primitivos y String — cero sobrecarga, el valor se inserta en el bytecode. Para métodos, no hay sobrecarga a menos que el método sea inline. En la mayoría de los casos, companion object no crea ningún impacto medible en el rendimiento. Usa @JvmStatic solo para API pública llamada desde Java.

Resumen

  • companion object es un mecanismo de Kotlin para declarar miembros estáticos de clase, reemplazando Java static
  • Un companion object por clase — agrupa todos los elementos estáticos en un único objeto compañero
  • Acceso mediante el nombre de la clase: ClassName.method() o ClassName.Companion.method()
  • @JvmStatic y @JvmField exportan miembros como métodos y campos estáticos reales para Java
  • const val para primitivos y String — inserta el valor en tiempo de compilación con cero sobrecarga
  • Interfaces también soportan companion object para constantes y métodos fábrica
  • Companion object con nombre mejora la legibilidad del código y autodocumenta el propósito de los miembros estáticos

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también