Когда инициализируется companion object

Ответ

Companion object инициализируется при первом обращении к классу, в котором он объявлен, либо при первом обращении к самому companion object. Это происходит лениво (lazy initialization), аналогично статическим блокам в Java.

Пример:

class MyClass {
    companion object {
        init {
            println("Companion initialized")
        }

        const val CONST_VALUE = 42
    }
}

// Инициализация произойдет здесь:
val value = MyClass.CONST_VALUE

Важные особенности:

  1. Инициализируется только один раз (синглтон)
  2. Потокобезопасен (инициализация синхронизирована)
  3. Доступен без создания экземпляра класса

Ответ 18+ 🔞

А, ну это же про companion object в Kotlin! Давай разберём, как это работает, чтобы не было потом "ой, ёпта, а чё оно не так".

Представь себе класс — это как твоя квартира. Внутри неё живут обычные свойства и методы — это как ты сам, ходишь, чай пьёшь. А companion object — это типа встроенная кладовка в прихожей. Она принадлежит квартире, но чтобы в неё залезть, не надо каждый раз открывать дверь в гостиную и проходить через весь дом. Подошёл к двери квартиры, открыл дварцу в стеночке — и всё, ты в ней.

И главное — эта кладовка создаётся лениво. То есть её не строят, пока ты в неё первый раз не полезешь. Пока ты не сказал MyClass.CONST_VALUE, там пусто и тихо. Как только полез — ёперный театр! — раз! и кладовка построилась, загрузилась и выдала тебе твой CONST_VALUE.

Вот смотри на код, тут всё понятно:

class MyClass {
    companion object {
        init {
            println("Companion initialized")
        }

        const val CONST_VALUE = 42
    }
}

// Инициализация произойдет здесь:
val value = MyClass.CONST_VALUE

До этой строчки val value = MyClass.CONST_VALUE твой companion object — это просто идея, чертёж. Он нихуя не делает. Но как только ты к нему обратился — вжух! — выполняется блок init, создаётся объект-компаньон (один на весь класс, синглтон, блять) и тебе отдаётся константа.

И три главных фишки, которые надо запомнить, а то будешь потом бздеть, что что-то не работает:

  1. Создаётся один раз и навсегда. Это синглтон. Не будет такого, что для каждого экземпляра MyClass своя кладовка. Нет, она одна на всех. Доверия ебать ноль к тому, кто говорит обратное.
  2. Потокобезопасен. Это значит, если два потока одновременно рванутся к CONST_VALUE в первый раз, они не создадут две кладовки. Один поток её построит, другой подождёт. Всё чинно, благородно, без гомосеков, налетевших на общий ресурс.
  3. Доступен без создания экземпляра класса. Это же и есть вся соль! Чтобы взять что-то из кладовки, тебе не надо заселяться в квартиру (создавать объект MyClass()). Подошёл к фасаду здания (к имени класса) — и всё, пользуйся. Удобно, хитрая жопа эти kotlin'овцы придумали.

Короче, если нужно место для констант, фабричных методов или какой-нибудь общей хуйни, которая логически привязана к классу, но не требует его инстанса — твоё место в companion object. Просто помни, что он ленивый, и инициализируется только когда его впервые потревожат.