Companion object у Kotlin: що це, синтаксис і застосування

Автор: IT Sectr Опубліковано: 2026-06-21 Час читання: 9 хв

companion object — механізм мови Kotlin, що замінює ключове слово static із Java для оголошення статичних членів класу. У Kotlin немає вбудованого static — натомість використовується оголошення object із модифікатором companion всередині класу. За даними JetBrains, 2025, companion object дозволяє викликати методи та властивості через ім'я класу, що робить їх повним аналогом статичних членів у Java-екосистемі.

Головне

  • companion object — це object declaration всередині класу з ключовим словом companion, що замінює Java static
  • Статичні члени доступні через ім'я класу без створення екземпляра: ClassName.method()
  • Іменований companion object дозволяє задати ім'я об'єкту для більш читабельного коду
  • Інтерфейси у Kotlin також можуть містити companion object із реалізацією методів
  • @JvmStatic — анотація для експорту методів companion object як справжніх static-методів у Java

Що таке companion object у Kotlin?

companion object — це спеціальний різновид object declaration у мові Kotlin, який маркується ключовим словом companion. Він дозволяє оголосити члени, що належать класу, а не його екземплярам — тобто статичні члени в термінах Java. На відміну від Java, де static є модифікатором для окремих полів і методів, у Kotlin статичні члени групуються всередині одного об'єкта-компаньйона.

Будь-який клас у Kotlin може містити рівно один companion object. Члени цього об'єкта доступні через ім'я класу без створення екземпляра: MyClass.method(). З точки зору байт-коду companion object компілюється в окремий внутрішній клас, а його методи стають статичними методами зовнішнього класу при використанні анотації @JvmStatic.

За даними Google I/O 2024, companion object став основним патерном для фабричних методів, констант і службових функцій у сучасних Android-додатках на Kotlin. Розробники обирають його замість класів-утиліт із пакетними функціями, оскільки companion object зберігає логічний зв'язок із класом-власником.

Використовуйте companion object для групування статичного контексту — констант, фабрик, допоміжних методів, які логічно належать до класу, але не потребують екземпляра.

Синтаксис companion object: оголошення та доступ

Базовий синтаксис companion object простий: ключове слово companion ставиться перед оголошенням object всередині класу. Якщо ім'я не вказано, об'єкт отримує ім'я Companion, до якого можна звертатися явно або неявно.

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

У наведеному прикладі TABLE_NAME та create() доступні через User.TABLE_NAME та User.create(). Зверніть увагу на модифікатор const для примітивних констант — він гарантує вбудовування значення на етапі компіляції, аналогічно Java static final для примітивів і String.

Неявний та явний доступ через Companion

Якщо companion object не має імені, до нього можна звернутися через автоматичне ім'я Companion: User.Companion.TABLE_NAME. На практиці це потрібно рідко, але корисно при виклику з Java-коду або при використанні рефлексії.

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

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

Іменований companion object та особливості

companion object може мати ім'я, що покращує читабельність коду та дозволяє звертатися до нього за зрозумілим іменем. Factory — найпоширеніше ім'я для companion object, що використовується як фабрика.

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

Іменований companion object допомагає документувати призначення статичних членів. У рефакторингу ім'я робить код самодокументованим — розробник одразу бачить, що Factory створює екземпляри HttpResponse.

Обмеження: рівно один companion object на клас

Клас може містити лише один companion object. Це принципова відмінність від Java, де можна оголосити будь-яку кількість статичних полів і методів без групування. Якщо потрібно кілька логічних груп статичних членів, використовуйте вкладені object declarations без companion.

За даними офіційної документації Kotlin (Kotlin Docs, 2025), обмеження на один companion object мотивоване дизайном мови: статичні члени повинні бути тісно пов'язані з класом, і один об'єкт-компаньйон забезпечує чітку межу цього зв'язку. Якщо статичних членів занадто багато — це сигнал до рефакторингу класу.

Companion object в інтерфейсах

У Kotlin інтерфейси також можуть містити companion object. Це дозволяє визначати статичні методи та константи безпосередньо всередині інтерфейсу, що неможливо в Java. Такий підхід часто використовується для оголошення констант, пов'язаних з інтерфейсом, або фабричних методів.

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

У цьому прикладі BASE_URL, TIMEOUT_MS та create() належать інтерфейсу ApiService, а не його реалізаціям. Це зручно: всі константи та фабрична логіка для створення екземпляра API-сервісу знаходяться в одному місці — всередині самого інтерфейсу.

Реалізації інтерфейсу не успадковують члени companion object — вони викликаються тільки через ім'я інтерфейсу: ApiService.BASE_URL.

@JvmStatic та @JvmField: сумісність із Java

При виклику методів companion object із Java-коду вони за замовчуванням доступні як методи вкладеного класу Companion, а не як статичні методи зовнішнього класу. Щоб експортувати їх як справжні static методи та поля для Java, використовуйте анотацію @JvmStatic для методів і @JvmField для полів.

АнотаціяЗастосуванняРезультат у Java
@JvmStaticМетоди companion objectСтатичний метод: ClassName.method()
@JvmFieldПоля companion objectСтатичне поле: ClassName.field
constПримітиви та StringInline-константа: компілятор підставляє значення
без анотаціїМетоди/поля за замовчуваннямCompanion.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

Використання @JvmStatic рекомендується для всіх публічних методів companion object, які повинні бути доступні з Java-коду. const застосовується тільки до примітивних типів і String — для інших типів використовуйте @JvmField.

Практичні приклади використання companion object

У реальних проектах companion object застосовується для кількох стандартних сценаріїв. Фабричні методи — найпоширеніший патерн: замість безлічі конструкторів із різними сигнатурами використовують іменовані фабричні методи в 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 у NetworkResult надає фабричний метод loading(), який створює екземпляр Loading із правильним generic-типом. Без цього методу довелося б створювати екземпляр напряму через Loading(), що розкриває внутрішню реалізацію.

Константи та теги для логування

Часто companion object використовується для зберігання констант, специфічних для класу. Константи, оголошені з const val, вбудовуються на етапі компіляції, що дає нульовий overhead у рантаймі.

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

Часті запитання

Чим companion object відрізняється від звичайного object у Kotlin?

Звичайний object — це повноцінний синглтон, що існує незалежно від класу. companion object — це object всередині класу, члени якого викликаються через ім'я зовнішнього класу. У байт-коді companion object стає статичним вкладеним класом, а звичайний object — автономним класом-синглтоном.

Чи можна успадкувати companion object?

Ні, companion object не успадковується підкласами. Якщо клас B успадковує клас A, то B.method() не викличе метод із companion object класу A — потрібно звертатися через A.method(). Це відповідає поведінці статичних методів у Java.

Як викликати companion object із Java-коду?

За замовчуванням — через ClassName.Companion.method(). Щоб викликати як статичний метод, додайте @JvmStatic до методу companion object. Для полів використовуйте @JvmField або оголосіть їх із const val для примітивів.

Чому в Kotlin немає ключового слова static?

Розробники Kotlin вирішили відмовитися від static на користь companion object для єдинообразної роботи з об'єктами. static у Java порушує принципи ООП, оскільки статичні методи не пов'язані з екземпляром. companion object — це об'єкт першого класу, який можна передавати, розширювати функціями-розширеннями та реалізовувати інтерфейси.

Чи впливає companion object на продуктивність?

При використанні const val для примітивів і String — нульовий overhead, значення вбудовується в байт-код. Для методів overhead відсутній, якщо метод не є inline. У більшості випадків companion object не створює вимірного впливу на продуктивність. Використовуйте @JvmStatic тільки для публічного API, що викликається з Java.

Підсумки

  • companion object — механізм Kotlin для оголошення статичних членів класу, що замінює Java static
  • Один companion object на клас — групує всі статичні елементи в одному об'єкті-компаньйоні
  • Доступ через ім'я класу: ClassName.method() або ClassName.Companion.method()
  • @JvmStatic та @JvmField експортують члени як справжні статичні методи та поля для Java
  • const val для примітивів і String — вбудовує значення на етапі компіляції без overhead
  • Інтерфейси також підтримують companion object для констант і фабричних методів
  • Іменований companion object покращує читабельність коду та самодокументує призначення статичних членів

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також