Почему мы используем "объект-компаньон" как своего рода замену статическим полям 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