Kotlin Object Keyword
Object keyword
In many object-oriented programming languages, a typical way to implement the Singleton pattern is to make the class constructor private, store an instance in a private static member, and return the same cached instance through a factory method.
Kotlin, however, does not have an explicit static modifier. So how should a Singleton be implemented?
This page introduces how to use Kotlin’s object keyword and how to implement a Singleton.
There are three main uses of object: object expressions, object declarations, and companion objects.
Object expression
An object expression creates an instance of an anonymous class. It can override properties and methods from an existing class.
In the example below, the MouseAdapter class is redefined, an anonymous instance is created, and that instance is passed as an argument to addMouseListener().
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { /*...*/ }
override fun mouseEntered(e: MouseEvent) { /*...*/ }
})
Object declaration (Singleton)
In Kotlin, declaring an object with the object keyword creates a singleton class that has exactly one instance.
The following example creates a singleton object named Config.
object Config {
var maxCount = 100
}
fun main() {
println(Config.maxCount)
}
Output:
100
Methods on a singleton can be called like static methods, using ClassName.methodName.
object Foo {
fun hello() = println("Hello!")
}
fun main() {
Foo.hello()
}
Output:
Hello!
Next, implement a class that stores list data.
object FruitStore {
private val fruits = mutableListOf<String>()
fun add(s: String) {
fruits.add(s)
}
fun printList() {
for (item in fruits) {
println(item)
}
}
}
fun main() {
FruitStore.add("Apple")
FruitStore.add("Orange")
FruitStore.add("Banana")
FruitStore.printList()
}
Output:
Apple
Orange
Banana
Code that uses this class can call its methods without creating an instance.
Companion Object (static methods)
companion object is used to define static-like methods inside a class.
class Math {
companion object {
fun add(a: Int, b: Int) = a + b
}
}
fun main() {
println(Math.add(3, 5))
}
Output:
8
Next, implement a singleton-style class that stores list data.
class FruitFactoryStore {
companion object Factory {
private val items = mutableListOf<String>()
fun create(): FruitFactoryStore = FruitFactoryStore()
}
fun add(s: String) {
items.add(s)
}
fun printList() {
for (item in items) {
println(item)
}
}
}
fun main() {
val store = FruitFactoryStore.create()
store.add("Apple")
store.add("Orange")
store.add("Banana")
store.printList()
println("-")
val store2 = FruitFactoryStore.create()
store2.printList()
}
Output:
Apple
Orange
Banana
------
Apple
Orange
Banana
The result shows that even though no items were added to store2, the data is still printed.
In the example above, the companion object is given the convenient name Factory after companion object, but that name is optional. When calling it, you do not need to specify Factory; you can call the method as if it were a direct method of the class.