Kotlin extends the classical concept of singleton through the object keyword. It implements the following patterns:
object Logger { ... }).Example of a singleton object:
object DatabaseManager { fun connect() { /*...*/ } } DatabaseManager.connect()
Object Expression:
val listener = object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { /*...*/ } }
Companion Object:
class User { companion object Factory { fun create(name: String) = User() } } val user = User.create("Ivan")
Nuances:
What is the difference between a companion object and an object declaration? Are all their members accessible as static?
Answer:
object declaration — global singleton, a member of a class, interface, or external scope.companion object — a special type of object declaration within a class, whose members can be called as if they were static (via the class name). However, unlike Java, they are actually fields of the singleton object.Example of the difference:
class A { companion object { fun foo() {} } object NestedObj { fun bar() {} } } A.foo() // OK A.NestedObj.bar() // OK, but this is not a static method
Story
A developer defined mutable state inside an object declaration and began using it from different threads without synchronization, not considering that singleton objects are shared across the entire application and could lead to race conditions.
Story
When declaring an object instead of a companion object within a class, the use of static methods was required, but they had to be called through the instance, which worsened readability and caused errors when migrating from Java.
Story
In UI code, a programmer created a new object each time through an object expression for an event handler. They mistakenly believed there was a singleton and state would be preserved; as a result, memory leaks occurred due to improper handling of the lifecycle.