Почему мы используем "объект-компаньон" как своего рода замену статическим полям Java в Котлине?
Каково предполагаемое значение "сопутствующего объекта"? До сих пор я использовал его только для замены Java static
, когда мне это нужно.
Я смущен:
- Почему он называется "компаньон"?
- Означает ли это, что для создания нескольких статических свойств мне нужно сгруппировать их внутри блока
companion object
?
- Чтобы мгновенно создать экземпляр singleton, охваченный классом, я часто пишу
:
companion object {
val singleton by lazy { ... }
}
который кажется унифицированным способом сделать это. Какой лучший способ?
Ответы
Ответ 1
-
Что подразумевается под "сопутствующим объектом"? Почему это называется "компаньон"?
Во-первых, Kotlin не использует концепцию Java static
членов, потому что Kotlin имеет свою собственную концепцию object
s для описания свойств и функций, связанных с одноэлементным состоянием, а static
часть Java класса может быть элегантно выражена в терминах синглтона: одноэлементный объект, который может быть вызван именем класса. Отсюда и название: это объект, который поставляется с классом.
Раньше его именем были class object
default object
, но затем он был переименован в companion object
что более понятно и также соответствует объектам-компаньонам Scala.
Помимо имен, он более мощный, чем static
члены Java: он может расширять классы и интерфейсы, и вы можете ссылаться на него и передавать его, как и другие объекты.
-
Означает ли это, что для создания нескольких статических свойств я должен сгруппировать их вместе в блоке companion object
?
Да, это идиоматический способ. Или вы можете даже сгруппировать их в объекты-компаньоны по их значению:
class MyClass {
object IO {
fun makeSomethingWithIO() { /* ... */ }
}
object Factory {
fun createSomething() { /* ... */ }
}
}
-
Чтобы мгновенно создать одноэлементный экземпляр, относящийся к классу, я часто пишу /*...*/
что выглядит как однотипный способ сделать это. Что лучше?
Это зависит от того, что вам нужно в каждом конкретном случае. Ваш код хорошо подходит для хранения состояния, связанного с классом, который инициализируется при первом обращении к нему.
Если вам не нужно, чтобы он был связан с классом, просто используйте объявление объекта:
object Foo {
val something by lazy { ... }
}
Вы также можете удалить lazy {... }
делегирование, чтобы инициализировать свойство при использовании первого класса, как статические инициализаторы Java
Вы также можете найти полезные способы инициализации одноэлементного состояния.
Ответ 2
Почему он называется "компаньон"?
Этот объект является компаньоном экземпляров.
IIRC была продолжительная дискуссия здесь: upcoming-change-class-objects-rethought
Означает ли это, что для создания нескольких статических свойств я должен сгруппировать их вместе внутри блока объектов-компаньонов?
Да. Каждое "статическое" свойство/метод должно быть помещено внутри этого компаньона.
Чтобы мгновенно создать экземпляр singleton, охваченный классом, я часто пишу
Вы не создаете экземпляр singleton мгновенно. Он создается при первом доступе к singleton
.
который кажется унифицированным способом сделать это. Какой лучший способ?
Скорее перейдите к object Singleton { }
, чтобы определить одноэлементный класс. Смотрите: Объявления объекта
Вам не нужно создавать экземпляр singleton
, просто используйте его так: Singleton.doWork()
Просто имейте в виду, что Котлин предлагает другие материалы для организации вашего кода. В настоящее время существуют альтернативы простым статическим функциям, например. вы могли бы использовать функции верхнего уровня.
Ответ 3
Почему это называется "компаньон"?
Объявление объекта внутри класса может быть помечено ключевым словом companion:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Члены объекта-компаньона можно вызывать, используя просто имя класса в качестве квалификатора:
val instance = MyClass.create()
Если вы используете только "объект" без "компаньон", вы должны сделать так:
val instance = MyClass.Factory.create()
В моем понимании "компаньон" означает, что этот объект является компаньоном с внешним классом.
Ответ 4
Можно сказать, что компаньон такой же, как "Статический блок", как Java, но в случае с Kotlin нет концепции статического блока, чем компаньон входит в кадр.
Как определить сопутствующий блок:
class Example {
companion object {
fun display(){
//place your code
}
}
}
Вызов метода сопутствующего блока, прямой с именем класса
Example.Companion.display