object Name { ... } declares a singleton directly in the language — exactly one instance ever exists, created lazily the first time it's accessed, with no separate singleton-pattern boilerplate needed. companion object { ... }, declared inside a class, attaches its members to the class itself rather than to instances — this is Kotlin's real substitute for Java's static, since Kotlin has no static keyword at all. Unlike static members, a companion object is a genuine object with its own identity, and can implement interfaces or have its own name.
object: a built-in singleton, no boilerplate
DatabaseConfig is accessed directly by name — there's exactly one instance, created the first time it's referenced, with none of the manual lazy-initialization code a singleton pattern requires in languages without this built in.
object DatabaseConfig {
val url = "jdbc:postgresql://localhost/mydb"
fun connect() = println("Connecting to $url")
}
DatabaseConfig.connect() // accessed directly — there's only ever ONE DatabaseConfigcompanion object: Kotlin's substitute for static
create() is called on the CLASS itself (User.create(...)), never on an instance — exactly the role a static factory method plays in Java, but expressed through a genuine object rather than a language keyword.
class User private constructor(val name: String) {
companion object {
fun create(name: String): User {
return User(name.trim())
}
}
}
val user = User.create(" Alice ") // called on the CLASS, like a static methodObject expressions: anonymous, one-off objects
Unlike an object DECLARATION (a named singleton), an object EXPRESSION creates a genuinely anonymous, one-off instance right where it's needed — conceptually similar to an anonymous class in Java.
interface ClickListener {
fun onClick()
}
val listener = object : ClickListener { // an anonymous, one-off object
override fun onClick() {
println("Clicked!")
}
}