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

Object Kotlin:类中对象和伴生对象之间的区别,object,kotlin,companion-object,Object,Kotlin,Companion Object,kotlin中类中的对象和伴生对象之间有什么区别 例如: class MyClass { object Holder { //something } companion object { //something } } 我已经读到,如果包含的参数/方法与其类密切相关,则应使用伴随对象 但是为什么在类中也可以声明普通对象呢?因为它的行为和同伴完全一样,但它必须有一个名字 它的“静态”(我来自java方面)生命周期是否有差异 伴生

kotlin中类中的对象和伴生对象之间有什么区别

例如:

class MyClass {

    object Holder {
        //something
    }

    companion object {
        //something
    }
}
我已经读到,如果包含的参数/方法与其类密切相关,则应使用伴随对象

但是为什么在类中也可以声明普通对象呢?因为它的行为和同伴完全一样,但它必须有一个名字


它的“静态”(我来自java方面)生命周期是否有差异

伴生对象之所以存在,是因为您可以像调用java静态方法/字段一样调用伴生对象的函数/属性。至于为什么允许您的
持有者
,没有理由说声明嵌套对象是非法的。它有时可能会派上用场。

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

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

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

有两种不同类型的
对象
使用,表达式声明

对象表达式

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

    button.setOnClickListener(object: View.OnClickListener() {
        override fun onClick(view: View) {
            // click event
        }
    })
需要注意的一点是,匿名内部类可以从封闭范围访问变量,并且这些变量不必是
final
。这意味着,在匿名内部类中使用的、未被视为
final
的变量在被访问之前可能会意外更改值

对象声明

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

    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()
调用伴生对象方法将如下所示

    var myClass = MyClass()
    myClass.instanceMethod()
    MyClass.actsAsStatic()

有关详细信息,请参阅。

当第一次访问对象或对象声明时,会延迟初始化


加载相应的类时,将初始化伴随对象。它带来了“静态”的本质,尽管Kotlin本身并不支持静态成员。

当类被加载时(通常是第一次被其他正在执行的代码引用时)会初始化一个伴生对象,而对象声明则是延迟初始化的,第一次访问时

请参阅下面的部分,清楚地定义了这两者之间的区别。

作为Kotlin的作用状态

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

当涉及普通对象和伴随对象时,唯一显著的区别是伴随对象的属性和函数可以通过使用包含类的名称直接访问,这使它看起来像java静态成员访问

例如,如果您有以下类

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

    companion object{
        fun foo() = "Hello World"
    }
}
然后,您可以按如下方式访问这两个对象 从包含类

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
在引擎盖下,每个对象声明都创建一个单例。 对于伴生对象,在包含类的静态初始值设定项中创建singleton对象。 但是,对于普通对象,当第一次访问对象类时,会延迟创建单例实例

通过编译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)
    }
}

A好的,初始化顺序有一些不同,区别是什么?我猜companion首先被初始化,因为它绑定到它的类,然后调用对象?companion对象是从包含类的静态构造函数初始化的,而普通对象是在第一次访问该对象时惰性地初始化的。这个答案不应该是正确的。接受这个答案只是误导。这个答案的最后一句显然是错误的。就生命周期而言,正如上面@llya所指出的,在类中声明的伴生对象和命名对象之间存在着绝对的区别。谢谢Mike!这应该是答案。如果伴生对象没有名称,我必须在伴生对象中使用
MyClass.MyCompanionObject.actsastatic()
MyClass.companion.actsastatic()
。这是新的变化,还是我做错了什么?谢谢。
object
用于单例,而
companion object
用于静态方法。提供了一个很好的用法解释。