Котлін: Різниця між об’єктом та супутнім об’єктом у класі


77

Яка різниця між об’єктом та супутнім об’єктом у класі в kotlin?

Приклад:

class MyClass {

    object Holder {
        //something
    }

    companion object {
        //something
    }
}

Я вже читав, що об'єкт-супутник буде використовуватися, якщо містять параметри / методи тісно пов'язані з його класом.

Але чому існує також можливість оголосити нормальний об'єкт у класі? Тому що він поводиться точно так, як супутник, але він повинен мати ім’я.

Чи є різниця в його "статичному" (я з боку Java) життєвому циклі?


3
objectдля одиночних і companion objectдля статичних методів. Kotlin - Декларації об’єктів дають хороші пояснення щодо використання.
ArtiomLK

Відповіді:


49

Об'єкти можуть реалізовувати інтерфейси. Усередині класу визначення простого об’єкта, який не реалізує жодного інтерфейсу, не має переваг у більшості випадків. Однак визначення декількох об'єктів, що реалізують різні інтерфейси (наприклад Comparator), може бути дуже корисним.

З точки зору життєвого циклу, немає різниці між супутнім об'єктом та іменованим об'єктом, оголошеним у класі.


Ідеально! Велике спасибі за пояснення!
Poweranimal

AFAIK є певна різниця в наказі про ініціалізацію
Ілля

Що таке різниця? Я гадаю, спочатку ініціюється companion, оскільки він прив’язаний до свого класу, а потім викликається об’єкт?
Poweranimal

32
Об'єкт-супутник ініціалізується із статичного конструктора класу, що містить, а звичайний об'єкт - ліниво при першому доступі до цього об'єкта.
Ілля

Ви відповіли, що я хочу ... "життєвий цикл". Дякую.
Licat Julius

60

Існує два різних типи objectвикористання, вираз та декларація .

Вираз об’єкта

Вираз об'єкта можна використовувати, коли клас потребує незначної модифікації, але не потрібно створювати для нього абсолютно новий підклас. Хорошим прикладом цього є анонімні внутрішні класи.

    button.setOnClickListener(object: View.OnClickListener() {
        override fun onClick(view: View) {
            // click event
        }
    })

Одного, на що слід звернути увагу, є те, що анонімні внутрішні класи можуть отримувати доступ до змінних із охоплюючої області, і ці змінні не повинні бути final. Це означає, що змінна, яка використовується всередині анонімного внутрішнього класу, не розглядаєтьсяfinal може несподівано змінити значення перед тим, як до нього отримати доступ.

Декларація об’єкта

Оголошення об'єкта подібне до оголошення змінної, і тому не може використовуватися в правій частині оператора присвоєння. Оголошення об'єктів дуже корисні для реалізації шаблону Singleton.

    object MySingletonObject {
        fun getInstance(): MySingletonObject {
            // return single instance of object
        }
    }

І тоді getInstanceметод можна викликати таким чином.

    MySingletonObject.getInstance()

Об'єкт-супутник

Супутній об’єкт - це конкретний тип оголошення об’єкта, що дозволяє об’єкту діяти подібно до статичних об’єктів іншими мовами (наприклад, Java). Додавання companionдо оголошення об’єкта дозволяє додати „статичну” функціональність до об’єкта, навіть якщо фактична статична концепція не існує в Kotlin. Ось приклад класу з методами екземпляра та методами супутника.

 class MyClass {
        companion object MyCompanionObject {
            fun actsAsStatic() {
                // do stuff
            }
        }

       fun instanceMethod() {
            // do stuff
        }
    }

Виклик методу екземпляра буде виглядати так.

    var myClass = MyClass()
    myClass.instanceMethod()

Виклик методу супутнього об'єкта буде виглядати так.

    MyClass.actsAsStatic()

Для отримання додаткової інформації див. Документи Kotlin .


2
Дякую Майку! Це має бути відповіддю.
Річі

2
Я повинен був використовувати метод всередині об'єкта компаньйона MyClass.MyCompanionObject.actsAsStatic()або MyClass.Companion.actsAsStatic()якщо об'єкт компаньйон не має назви. Це нова зміна, чи я зробив щось не так? Дякую.
Супрія

7

Об’єкт або оголошення об’єкта ініціалізується ліниво при першому доступі.

Об'єкт-супутник ініціалізується, коли завантажується відповідний клас. Це забезпечує "статичну" суть, хоча Котлін за своєю суттю не підтримує статичні члени.


7

Як Котлін в дії держав

Ключове слово object з’являється у Kotlin у багатьох випадках, але всі вони мають однакову суть ідеї: ключове слово визначає клас і одночасно створює екземпляр (іншими словами, об’єкт) цього класу.

коли мова йде про звичайний об’єкт та об’єкт-супутник, єдина суттєва відмінність полягає в тому, що властивості та функції супутнього об’єкта можна отримати безпосередньо за допомогою імені вміщуваного класу, що робить його схожим на доступ статичного члена Java.

наприклад, якщо у вас є наступний клас

class Temp{
    object Holder{
        fun foo() = 1
    }

    companion object{
        fun foo() = "Hello World"
    }
}

тоді ви можете отримати доступ до обох цих об'єктів як наступний From, що містить клас

foo()   // call to companion object function
Holder.foo() // call to plain object function

та поза межами класу

Temp.foo() // call to companion object function
Temp.Holder.foo() // call to plain object function

Під капотом кожне оголошення об'єкта створює синглтон. у випадку супутнього об'єкта односторонній об'єкт створюється в статичному ініціалізаторі, що містить клас. але у випадку звичайних об'єктів екземпляр однотонній створюється ліниво при першому зверненні до класу об'єктів.

Ви можете переконатися в цьому самі, скомпілювавши клас kotlin, а потім декомпілюючи згенеровані файли класів, використовуючи якийсь декомпілятор Java.

Щодо того, чому існує також можливість оголосити нормальний об’єкт у класі, розглянемо наступний клас, де об’єкт-член дуже корисний.

data class Employee(val name: String) {
    object NameComparator : Comparator<Employee> {
         override fun compare(p1: Employee, p2: Employee): Int =
             p1.name.compareTo(p2.name)
    }
}

тепер ми можемо сортувати список співробітників як

list.sortedWith(Employee.NameComparator))

3

Об'єкт-супутник існує, оскільки ви можете викликати функції / властивості об'єктів-супутників, як це статичний метод / поле Java. І тому, чому ваш Holderдозвіл дозволений, ну, немає жодної причини, що оголошення вкладеного об’єкта є незаконним. Іноді це може стати в нагоді.


2

Об'єкт компаньйон инициализируется , коли клас завантажується ( як правило , в перший раз , він посилається інший код , який виконується) , тоді як об'єкт декларація Ініціалізувати ліниво, при зверненні в перший раз.

Будь ласка, зверніться до https://kotlinlang.org/docs/reference/object-declarations.html, нижній розділ чітко визначає різницю між цими двома.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.