Ответ
Оба используются для реализации паттерна 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для членов спутника). - Основное назначение:
- Фабричные методы (альтернатива конструкторам).
- Константы, специфичные для класса.
- Может реализовывать интерфейсы.
- Может иметь имя (например,
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) |
|
| Наследование | Может наследовать классы и реализовывать интерфейсы | Может реализовывать интерфейсы |
Ответ 18+ 🔞
Слушай, а вот этот твой вопрос про object и companion object — это ж классика, блядь! Прям как в анекдоте про двух близнецов, где один в глобальной видимости, а другой при мамке сидит. Ёпта, сейчас разжуем.
Ну смотри, оба эти придурка нужны, чтобы сделать Singleton, то есть такую сущность, которая в единственном экземпляре, как последняя бутылка пива в холодильнике в три часа ночи. Но разница — пиздец какая принципиальная!
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, только поумнее.
- Где он торчит? Внутри класса. Доступ через имя класса, типа
ИмяКласса.ИмяЧленаСпутника. - Зачем он нужен? Вот тут интереснее, ёпта!
- Фабричные методы. Когда конструкторы — говно, а тебе надо создавать объекты хитро.
- Константы класса. Не глобальные, а именно для этого класса.
- Может даже интерфейсы реализовывать, не лыком шит!
- Может иметь своё имя (например,
companion object Loader), чтобы не быть анонимным пидором.
- Пример, чтобы стало совсем ясно:
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") // Видишь? User.метод val name = User.DEFAULT_NAME
| А теперь, блядь, главные различия, чтобы не путать: | Признак | object |
companion object |
|---|---|---|---|
| С кем живёт? | Самодостаточный мужик, одиночка. | Сынок, привязан к родительскому классу. | |
| На что похож в Java? | public static final класс с приватным конструктором. |
Просто статические методы и поля внутри класса. | |
| Как до него достучаться? | По имени объекта: AppConfig.что-то. |
Через имя внешнего класса: User.что-то. |
|
| Может ли наследоваться? | Да, может и классы наследовать, и интерфейсы пихать. | Только интерфейсы реализовывать, наследовать классы — низя. |
Короче, если тебе нужна глобальная штука на весь проект — бери object. Если нужна статика, привязанная к логике конкретного класса (фабрики, константы) — твой выбор companion object. Всё просто, как три копейки, блядь!