Phase 3 · Object-Oriented KotlinModule 17~32 min read

Objects, Companion Objects & Singletons

Singletons and factories with object declarations and companion objects.

What you'll learn

Kotlin has no static keyword. Instead it offers something cleaner: the object declaration for singletons, and the companion object for class-level members and factories. This module covers all the ways to use object.

By the end you'll be able to:

  • Create singletons with object
  • Make one-off anonymous objects with object expressions
  • Add class-level members and factory methods with companion object

object declarations (singletons)

Declaring object Name creates a singleton — a class with exactly one instance, created lazily and thread-safely the first time it's used. You access its members directly on the name, never instantiating it. It's perfect for a shared registry, configuration, or manager:

Database.kt
object Database {                  // a SINGLETON — only ever one instance
    val connections = mutableListOf<String>()

    fun connect(name: String) {
        connections.add(name)
        println("Connected: $name")
    }
}

Database.connect("primary")        // access directly — no instantiation
Database.connect("replica")
println(Database.connections.size) // 2

Tip

This is the Singleton pattern with zero boilerplate — no private constructor, no getInstance(), no thread-safety code. Kotlin handles all of it. Use an object whenever you genuinely need exactly one instance.

Object expressions

An object expression creates an anonymous object on the spot — often to implement an interface for a single use, like an event listener. It's Kotlin's equivalent of a Java anonymous class:

ObjectExpr.kt
interface ClickListener {
    fun onClick()
}

// an object EXPRESSION creates a one-off anonymous object
val listener = object : ClickListener {
    override fun onClick() = println("Clicked!")
}

listener.onClick()

Note

For interfaces with a single method (like ClickListener), you can usually pass a lambda instead — even cleaner. Object expressions are for when you need to override multiple methods or hold state.

Companion objects

Since Kotlin has no static, how do you attach members to a class rather than its instances — like factory methods or constants? A companion object: a single object tied to the class, whose members you call on the class name itself:

User.kt
class User private constructor(val name: String) {
    companion object {
        fun create(name: String): User {   // a factory method
            println("Creating user...")
            return User(name)
        }
    }
}

val u = User.create("Sara")        // called on the CLASS, like a static method
println(u.name)

Key idea

A companion object is Kotlin's answer to static members. It's especially loved for factory methods — combined with a private constructor, you control exactly how instances are created (validating input, returning cached instances, choosing a subclass).

Recap & quick check

Key takeaways

  • Kotlin has no 'static'; 'object' and 'companion object' fill the gap.
  • object Name creates a lazy, thread-safe singleton accessed directly on the name.
  • Object expressions create one-off anonymous objects (like Java anonymous classes).
  • A companion object attaches class-level members (constants, factory methods) called on the class name.
  • Companion + private constructor is the idiomatic way to write factory methods.

Quick check

1. What does an 'object' declaration create?

2. Kotlin has no 'static' keyword. What replaces class-level members?

3. How do you access a companion object's function?

4. What is an object expression used for?

5. What's the idiomatic way to write a factory method in Kotlin?

Great — you've mastered Kotlin's take on statics and singletons. Next up: Module 18 — Sealed Classes & Enums.