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

在 Kotlin 的类中,对象和伴随对象的区别是什么?

例如:

class MyClass {


object Holder {
//something
}


companion object {
//something
}
}

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

但是为什么还有可能在类中声明一个普通对象呢?因为它的行为和同伴一模一样但它必须有名字。

在它的“ static”(我来自 Java 端)生命周期中是否存在差异?

38071 次浏览

Companion object exists because you can call companion objects' functions/properties like it is a java static method/field. And for why your Holder is allowed, well, there is no reason that declaring a nested object is illegal. It may comes in handy sometimes.

Objects can implement interfaces. Inside a class, defining a simple object that doesn't implement any interfaces has no benefit in most cases. However, defining multiple objects that implement various interfaces (e.g. Comparator) can be very useful.

In terms of lifecycle, there is no difference between a companion object and a named object declared in a class.

There are two different types of object uses, expression and declaration.

Object Expression

An object expression can be used when a class needs slight modification, but it's not necessary to create an entirely new subclass for it. Anonymous inner classes are a good example of this.

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

One thing to watch out for is that anonymous inner classes can access variables from the enclosing scope, and these variables do not have to be final. This means that a variable used inside an anonymous inner class that is not considered final can change value unexpectedly before it is accessed.

Object Declaration

An object declaration is similar to a variable declaration and therefore cannot be used on the right side of an assignment statement. Object declarations are very useful for implementing the Singleton pattern.

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

And the getInstance method can then be invoked like this.

MySingletonObject.getInstance()

Companion Object

A companion object is a specific type of object declaration that allows an object to act similar to static objects in other languages (such as Java). Adding companion to the object declaration allows for adding the "static" functionality to an object even though the actual static concept does not exist in Kotlin. Here's an example of a class with instance methods and companion methods.

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

fun instanceMethod() {
// do stuff
}
}

Invoking the instance method would look like this.

var myClass = MyClass()
myClass.instanceMethod()

Invoking the companion object method would look like this.

MyClass.actsAsStatic()

See the Kotlin docs for more info.

An object, or an object declaration, is initialized lazily, when accessed for the first time.

A companion object is initialized when the corresponding class is loaded. It brings about the 'static' essence, although Kotlin does not inherently support static members.

A Companion object is initialized when the class is loaded (typically the first time it's referenced by other code that is being executed) whereas Object declarations are initialized lazily, when accessed for the first time.

Please refer https://kotlinlang.org/docs/reference/object-declarations.html bottom section clearly defines the difference between these two.

As Kotlin in Action states

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.

when it comes to a plain object and a companion object, the only significant difference is that properties and functions of a companion object can be accessed directly by using the name of the containing class which makes it seem like java static member access.

for example if you have following class

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


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

then you can access both of these objects as following From containing class

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

and from outside the class

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

Under the hood every object declaration creates a singleton. in case of companion object the singleton object is created in the static initializer of the containing class. but in case of plain objects singleton instance is created lazily when the object class is accessed for the first time.

You can see it for yourself by compiling the kotlin class and then decompiling the generated class files using some java decompiler.

As to why there is also a possibility of declaring a normal object in the class, consider the following class where a member object is very useful.

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

now we can sort a list of employees as

list.sortedWith(Employee.NameComparator))