Почему мы используем «объект-компаньон» в качестве замены статических полей Java в Kotlin?

145

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

Я смущен с:

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

:

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

который выглядит как однотипный способ сделать это. Какой способ лучше?

Рэнди Сугианто 'Юку'
источник

Ответы:

108
  • Что подразумевается под «сопутствующим объектом»? Почему это называется «компаньон»?

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

    Раньше его имя было 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

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

горячая клавиша
источник
Хорошие и идиоматические примеры.
Trein
19

Почему это называется «компаньон»?

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

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

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

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

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

который выглядит как однотипный способ сделать это. Какой способ лучше?

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

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

D3xter
источник
7

Почему это называется «компаньон»?

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

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

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

val instance = MyClass.create()

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

val instance = MyClass.Factory.create()

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

Lyn
источник
«объект» без «компаньон» называется так (MyClass (). create ()). Как одноэлементный, но для доступа к одноэлементному объекту вы должны сначала инициализировать «внешний» класс.
LiTTle
0

Можно сказать, что компаньон такой же, как «Статический блок», как Java, но в случае с Kotlin нет концепции статического блока, чем компаньон входит в кадр.

Как определить сопутствующий блок:

class Example {
      companion object {
        fun display(){
        //place your code
     }
  }
}

Вызов метода сопутствующего блока, прямой с именем класса

Example.Companion.display
Анкур Ядав
источник