Kotlin:类中对象和伴随对象之间的区别

Pow*_*mal 63 object kotlin companion-object

kotlin中一个对象和一个伴侣对象有什么区别?

例:

class MyClass {

    object Holder {
        //something
    }

    companion object {
        //something
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经读过,如果包含的参数/方法与其类密切相关,则应使用伴随对象.

但为什么还有可能在类中声明一个普通的对象?因为它的行为与伴侣完全相同,但它必须具有名称.

它的"静态"(我来自java方面)生命周期可能有所不同吗?

Mik*_*ike 44

有两种不同类型的object用法,表达声明.

对象表达

当一个类需要稍微修改时,可以使用一个对象表达式,但是没有必要为它创建一个全新的子类.匿名内部类就是一个很好的例子.

    button.setOnClickListener(object: View.OnClickListener() {
        override fun onClick(view: View) {
            // click event
        }
    })
Run Code Online (Sandbox Code Playgroud)

需要注意的一点是,匿名内部类可以从封闭范围访问变量,而这些变量不一定是这样final.这意味着在匿名内部类中使用的未被考虑的变量在final访问之前可能会意外地更改值.

对象声明

对象声明类似于变量声明,因此不能在赋值语句的右侧使用.对象声明对于实现Singleton模式非常有用.

    object MySingletonObject {
        fun getInstance(): MySingletonObject {
            // return single instance of object
        }
    }
Run Code Online (Sandbox Code Playgroud)

getInstance方法然后可以调用这个样子.

    MySingletonObject.getInstance()
Run Code Online (Sandbox Code Playgroud)

伴随对象

伴随对象是一种特定类型的对象声明,它允许对象的行为类似于其他语言(如Java)中的静态对象.添加companion到对象声明允许向对象添加"静态"功能,即使Kotlin中不存在实际的静态概念.这是一个带有实例方法和伴随方法的类的示例.

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

       fun instanceMethod() {
            // do stuff
        }
    }
Run Code Online (Sandbox Code Playgroud)

调用实例方法看起来像这样.

    var myClass = MyClass()
    myClass.instanceMethod()
Run Code Online (Sandbox Code Playgroud)

调用伴随对象方法将如下所示.

    MyClass.actsAsStatic()
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅Kotlin文档.

  • 谢谢迈克!这应该是答案。 (2认同)
  • 如果随播对象没有名称,则必须在随播对象内部使用该方法作为“ MyClass.MyCompanionObject.actsAsStatic()”或“ MyClass.Companion.actsAsStatic()”。这是一个新的变化,还是我做错了什么?谢谢。 (2认同)

yol*_*ole 36

对象可以实现接口.在类中,定义一个不实现任何接口的简单对象在大多数情况下没有任何好处.但是,定义实现各种接口(例如Comparator)的多个对象可能非常有用.

就生命周期而言,伴随对象与类中声明的命名对象之间没有区别.

  • Companion对象从包含类的静态构造函数初始化,并且普通对象在第一次访问该对象时被懒惰地初始化. (17认同)

mig*_*WOZ 12

正如Kotlin 在行动中所说

在 Kotlin 中出现了很多情况下的 object 关键字,但它们都具有相同的核心思想:关键字定义一个类并同时创建该类的实例(换句话说,一个对象)。

对于普通对象和伴生对象,唯一显着的区别是伴生对象的属性和函数可以通过使用包含类的名称直接访问,这使得它看起来像java静态成员访问。

例如,如果您有以下课程

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

    companion object{
        fun foo() = "Hello World"
    }
}
Run Code Online (Sandbox Code Playgroud)

那么你可以访问这两个对象如下来自包含类

foo()   // call to companion object function
Holder.foo() // call to plain object function
Run Code Online (Sandbox Code Playgroud)

和课外

Temp.foo() // call to companion object function
Temp.Holder.foo() // call to plain object function
Run Code Online (Sandbox Code Playgroud)

在幕后,每个对象声明都会创建一个单例。如果是伴生对象,则在包含类的静态初始化程序中创建单例对象。但是在普通对象的情况下,当第一次访问对象类时会延迟创建单例实例。

您可以通过编译 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以将员工列表排序为

list.sortedWith(Employee.NameComparator))
Run Code Online (Sandbox Code Playgroud)


Sup*_*iya 9

当第一次访问时,对象或对象声明被懒惰地初始化.

加载相应的类时,将初始化伴随对象.虽然Kotlin本身并不支持静态成员,但它带来了"静态"本质.


小智 5

播对象类时被加载,而(典型地在第一时间它是由正在执行其他代码中引用)被初始化对象声明延迟初始化,在第一次访问时。

请参考https://kotlinlang.org/docs/reference/object-declarations.html底部明确定义了这两者之间的区别。