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))
object
for Singletons andcompanion object
for static methods. Kotlin - Object declarations provides a good usage explanation. – Lethe