Kotlin:class 中对象和伴生对象的区别
Kotlin: Difference between object and companion object in a class
kotlin 中 class 中的对象和伴随对象有什么区别?
示例:
class MyClass {
object Holder {
//something
}
companion object {
//something
}
}
我已经读到,如果包含的 parameters/methods 与其 class 密切相关,则应使用伴随对象。
但是为什么在class中也可以声明一个普通对象呢?因为它的行为和同伴完全一样,但它必须有一个名字。
它的 "static"(我来自 java 一方)生命周期是否可能有所不同?
伴生对象的存在是因为您可以调用伴生对象的 functions/properties,就像它是一个 java 静态 method/field。为什么你的 Holder
被允许,好吧,没有理由声明嵌套对象是非法的。有时可能会派上用场。
对象可以实现接口。在 class 中,定义一个不实现任何接口的简单对象在大多数情况下没有任何好处。但是,定义实现各种接口的多个对象(例如 Comparator
)可能非常有用。
就生命周期而言,伴生对象与在 class 中声明的命名对象没有区别。
有两种不同类型的 object
用法,表达式 和 声明.
对象表达式
当class需要稍微修改时,可以使用对象表达式,但没有必要为其创建一个全新的子class。匿名内部 classes 就是一个很好的例子。
button.setOnClickListener(object: View.OnClickListener() {
override fun onClick(view: View) {
// click event
}
})
需要注意的一件事是匿名内部 classes 可以从封闭范围访问变量,并且这些变量不必是 final
。这意味着在未被考虑 final
的匿名内部 class 中使用的变量可以在访问之前意外更改值。
对象声明
对象声明类似于变量声明,因此不能用在赋值语句的右侧。对象声明对于实现单例模式非常有用。
object MySingletonObject {
fun getInstance(): MySingletonObject {
// return single instance of object
}
}
然后可以像这样调用getInstance
方法。
MySingletonObject.getInstance()
伴随对象
伴随对象是一种特定类型的对象声明,它允许对象的行为类似于其他语言中的静态对象(例如Java)。向对象声明添加 companion
允许向对象添加“静态”功能,即使 Kotlin 中不存在实际的静态概念。这是一个带有实例方法和伴随方法的 class 示例。
class MyClass {
companion object MyCompanionObject {
fun actsAsStatic() {
// do stuff
}
}
fun instanceMethod() {
// do stuff
}
}
调用实例方法如下所示。
var myClass = MyClass()
myClass.instanceMethod()
调用伴随对象方法如下所示。
MyClass.actsAsStatic()
有关详细信息,请参阅 Kotlin docs。
对象或对象声明在第一次访问时被延迟初始化。
伴随对象在相应的 class 加载时被初始化。它带来了 'static' 本质,尽管 Kotlin 本身并不支持静态成员。
A Companion object 在 class 加载时初始化(通常是第一次被其他正在执行的代码引用)而 Object 声明在第一次访问时延迟初始化。
请参考https://kotlinlang.org/docs/reference/object-declarations.html底部清楚地定义了这两者之间的区别。
如Kotlin 实战所述
The object keyword comes up in Kotlin in a number of cases, but they
all share the same core idea: the keyword defines a class and creates
an instance (in other words, an object) of that class at the same
time.
当谈到普通对象和伴生对象时,唯一显着的区别是伴生对象的属性和函数可以通过使用包含 class 的名称直接访问,这使得它看起来像 java 静态成员访问。
例如,如果您有以下 class
class Temp{
object Holder{
fun foo() = 1
}
companion object{
fun foo() = "Hello World"
}
}
然后你可以访问这两个对象如下
来自包含class
foo() // call to companion object function
Holder.foo() // call to plain object function
并且来自 class
之外
Temp.foo() // call to companion object function
Temp.Holder.foo() // call to plain object function
在幕后,每个对象声明都会创建一个单例。
在伴随对象的情况下,单例对象是在包含 class 的静态初始值设定项中创建的。
但是对于普通对象,单例实例是在第一次访问对象 class 时延迟创建的。
您可以通过编译 kotlin class 然后使用一些 java 反编译器反编译生成的 class 文件来亲眼看到它。
至于为什么还有可能在class中声明一个普通对象,请考虑下面class成员对象非常有用的地方。
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))
kotlin 中 class 中的对象和伴随对象有什么区别?
示例:
class MyClass {
object Holder {
//something
}
companion object {
//something
}
}
我已经读到,如果包含的 parameters/methods 与其 class 密切相关,则应使用伴随对象。
但是为什么在class中也可以声明一个普通对象呢?因为它的行为和同伴完全一样,但它必须有一个名字。
它的 "static"(我来自 java 一方)生命周期是否可能有所不同?
伴生对象的存在是因为您可以调用伴生对象的 functions/properties,就像它是一个 java 静态 method/field。为什么你的 Holder
被允许,好吧,没有理由声明嵌套对象是非法的。有时可能会派上用场。
对象可以实现接口。在 class 中,定义一个不实现任何接口的简单对象在大多数情况下没有任何好处。但是,定义实现各种接口的多个对象(例如 Comparator
)可能非常有用。
就生命周期而言,伴生对象与在 class 中声明的命名对象没有区别。
有两种不同类型的 object
用法,表达式 和 声明.
对象表达式
当class需要稍微修改时,可以使用对象表达式,但没有必要为其创建一个全新的子class。匿名内部 classes 就是一个很好的例子。
button.setOnClickListener(object: View.OnClickListener() {
override fun onClick(view: View) {
// click event
}
})
需要注意的一件事是匿名内部 classes 可以从封闭范围访问变量,并且这些变量不必是 final
。这意味着在未被考虑 final
的匿名内部 class 中使用的变量可以在访问之前意外更改值。
对象声明
对象声明类似于变量声明,因此不能用在赋值语句的右侧。对象声明对于实现单例模式非常有用。
object MySingletonObject {
fun getInstance(): MySingletonObject {
// return single instance of object
}
}
然后可以像这样调用getInstance
方法。
MySingletonObject.getInstance()
伴随对象
伴随对象是一种特定类型的对象声明,它允许对象的行为类似于其他语言中的静态对象(例如Java)。向对象声明添加 companion
允许向对象添加“静态”功能,即使 Kotlin 中不存在实际的静态概念。这是一个带有实例方法和伴随方法的 class 示例。
class MyClass {
companion object MyCompanionObject {
fun actsAsStatic() {
// do stuff
}
}
fun instanceMethod() {
// do stuff
}
}
调用实例方法如下所示。
var myClass = MyClass()
myClass.instanceMethod()
调用伴随对象方法如下所示。
MyClass.actsAsStatic()
有关详细信息,请参阅 Kotlin docs。
对象或对象声明在第一次访问时被延迟初始化。
伴随对象在相应的 class 加载时被初始化。它带来了 'static' 本质,尽管 Kotlin 本身并不支持静态成员。
A Companion object 在 class 加载时初始化(通常是第一次被其他正在执行的代码引用)而 Object 声明在第一次访问时延迟初始化。
请参考https://kotlinlang.org/docs/reference/object-declarations.html底部清楚地定义了这两者之间的区别。
如Kotlin 实战所述
The object keyword comes up in Kotlin in a number of cases, but they all share the same core idea: the keyword defines a class and creates an instance (in other words, an object) of that class at the same time.
当谈到普通对象和伴生对象时,唯一显着的区别是伴生对象的属性和函数可以通过使用包含 class 的名称直接访问,这使得它看起来像 java 静态成员访问。
例如,如果您有以下 class
class Temp{
object Holder{
fun foo() = 1
}
companion object{
fun foo() = "Hello World"
}
}
然后你可以访问这两个对象如下 来自包含class
foo() // call to companion object function
Holder.foo() // call to plain object function
并且来自 class
之外Temp.foo() // call to companion object function
Temp.Holder.foo() // call to plain object function
在幕后,每个对象声明都会创建一个单例。 在伴随对象的情况下,单例对象是在包含 class 的静态初始值设定项中创建的。 但是对于普通对象,单例实例是在第一次访问对象 class 时延迟创建的。
您可以通过编译 kotlin class 然后使用一些 java 反编译器反编译生成的 class 文件来亲眼看到它。
至于为什么还有可能在class中声明一个普通对象,请考虑下面class成员对象非常有用的地方。
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))