Почему мы используем "сопутствующий объект" как своего рода замену для статических полей Java в Котлине?


каково Предполагаемое значение "сопутствующего объекта"? До сих пор я использовал его только для замены Java static когда мне это нужно.

Я смущен с:

  • почему это называется "спутник"?
  • означает ли это, что для создания нескольких статический свойства, я должен сгруппировать его вместе внутри companion object заблокировать?
  • чтобы мгновенно создать одноэлементный экземпляр, который относится к классу, я часто пиши

:

companion object {
    val singleton by lazy { ... }
}

что похоже на однотипный способ сделать это. Что может быть лучше?

3 109

3 ответа:

  • каково Предполагаемое значение "сопутствующего объекта"? Почему это называется "компаньон"?

    во-первых, Котлин не использует концепцию Java static членов, потому что Котлин имеет свой собственный на objects для описания свойств и функций, связанных с одноэлементным состоянием, и Java static часть класса может быть элегантно выражена в терминах синглтона: это одноэлементный объект, который может быть вызван классом' имя. Отсюда и название: это объект, который входит в класс.

    его имя раньше было class object и default object, а потом он был переименован в companion object, которая является более четкой, а также в соответствии с Scala companion objects.

    помимо именования, он более мощный, чем Java static члены: он может расширять классы и интерфейсы, и вы можете ссылаться и передавать его так же, как и другие объекты.

  • означает ли это, что для создания нескольких статических свойств, я должен сгруппировать его вместе внутри companion object заблокировать?

    Да, это идиоматический способ. Или вы даже можете сгруппировать их в несопровождаемые объекты по их значению:

    class MyClass {
        object IO {
            fun makeSomethingWithIO() { /* ... */ }
        }
    
        object Factory {
            fun createSomething() { /* ... */ }
        }
    }
    
  • чтобы мгновенно создать одноэлементный экземпляр, который относится к классу, я часто пишу /*...*/ что похоже на однотипный способ сделать это. Что может быть лучше?

    это зависит от того, что необходимо в каждом конкретном случае. Ваш код хорошо подходит для хранения состояния, привязанного к классу, который инициализируется при первом вызове к нему.

    Если вам не нужно, чтобы он был связан с классом, просто используйте объявление объекта:

    object Foo {
        val something by lazy { ... }
    }
    

    вы также можете удалить lazy { ... } делегация чтобы сделать свойство инициализировать при использовании первого класса, так же, как Java static инициализаторы

    вы также можете найти полезные способы инициализация синглтона государства.

почему это называется "спутник"?

этот объект является спутником экземпляров. Кажется, там была продолжительная дискуссия здесь: предстоящее-изменение-класс-объекты-переосмыслено

означает ли это, что для создания нескольких статических свойств я должен сгруппировать их вместе внутри блока сопутствующих объектов?

да. Каждое "статическое" свойство / метод должно быть помещено внутри этого компаньона.

To мгновенно создать одноэлементный экземпляр, который относится к классу, я часто пишу

вы не создаете одноэлементный экземпляр мгновенно. Он создается при доступе singleton в первый раз.

что похоже на однотипный способ сделать это. Что может быть лучше?

С object Singleton { } для определения одноэлементного класса. Смотрите:Объявление Вам не нужно создавать экземпляр Singleton, просто использовать это вот так Singleton.doWork()

просто имейте в виду, что Котлин предлагает другие вещи для организации вашего кода. Теперь есть альтернативы простым статическим функциям, например, вы можете использовать функции верхнего уровня.

Почему это называется "спутник"?

объявление объекта внутри класса может быть отмечено ключевым словом companion:

class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}

члены сопутствующего объекта могут быть вызваны с помощью простого имени класса в качестве квалификатора:

val instance = MyClass.create()

Если вы используете только "объект" без "компаньона", вы должны сделать так:

val instance = MyClass.Factory.create()

в моем понимании, "компаньон" означает, что этот объект является компаньоном с внешним классом.