В чем разница между object и companion object в Kotlin?

«В чем разница между object и companion object в Kotlin?» — вопрос из категории ООП, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Оба используются для реализации паттерна Singleton (Одиночка), но с разной областью видимости и назначением.

object (Объект объявления)

  • Что это: Самостоятельный синглтон. Объявление object одновременно объявляет класс и создает его единственный экземпляр с именем объекта.
  • Область видимости: Глобальная (в пределах своего пакета и видимости).
  • Основное назначение: Утилитные классы, фасады, репозитории, хранилища глобального состояния.
  • Пример:
    object AppConfig {
        const val API_URL = "https://api.example.com"
        val appVersion: String by lazy { loadVersionFromFile() }
        fun log(message: String) { println("[App]: $message") }
    }
    // Использование
    val url = AppConfig.API_URL
    AppConfig.log("Started")

companion object (Спутник)

  • Что это: Синглтон, привязанный к классу, в котором он объявлен. Аналог статических членов в Java, но более мощный.
  • Область видимости: Внутри класса, через имя класса (ClassName.Companion или просто ClassName для членов спутника).
  • Основное назначение:
    1. Фабричные методы (альтернатива конструкторам).
    2. Константы, специфичные для класса.
    3. Может реализовывать интерфейсы.
    4. Может иметь имя (например, companion object Factory).
  • Пример:
    class User private constructor(val id: String) {
        companion object {
            // Фабричный метод
            fun createWithEmail(email: String): User {
                val id = generateIdFromEmail(email)
                return User(id)
            }
            // Константа
            const val DEFAULT_NAME = "Guest"
        }
    }
    // Использование
    val user = User.createWithEmail("test@example.com")
    val name = User.DEFAULT_NAME
Ключевые различия: Признак object companion object
Связь с классом Самостоятельная сущность Вложен в класс, является его частью
Аналог в Java public static final класс с приватным конструктором Статические методы и поля внутри класса
Доступ к членам Через имя объекта (AppConfig.API_URL) Через имя внешнего класса (User.DEFAULT_NAME)
Наследование Может наследовать классы и реализовывать интерфейсы Может реализовывать интерфейсы