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 для primitives и 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?

ordinary 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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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