skip to content

What can an `object` declaration do that constructors-and-classes can't, and where can object declarations be placed (top-level vs nested)? Cover interface implementation, inheritance, and nesting.

level: seniorimportance: nice to knowfreq 35%

answer

  1. Implements interfaces, extends one open class
  2. No constructor; can't be subclassed or `open`/`inner`
  3. Top-level OR nested (Outer.Nested), still one global instance
  4. Nested object != tied to an outer instance
  5. Use for stateless strategies, sentinels, comparators

basics

~20 s

An object can be declared at the top level or nested inside a class. It can implement interfaces and extend a class, but it can't have a constructor. A nested object is still a single shared instance.

solid answer

~40 s

An `object` declaration is a full type with one instance. It **can implement interfaces and extend one open class**, so it serves as a ready-made singleton implementation (e.g., a default `Comparator`, an empty/no-op strategy). It **cannot have constructors or constructor parameters**, and you can't subclass it (no instances to vary). Placement: it can be **top-level** or **nested inside a class** (a nested `object` is accessed as `Outer.Nested` and is still a singleton, independent of any outer instance). It can also be declared as a `private`/`internal` member to scope visibility. Unlike an inner class, a nested object holds no reference to an enclosing instance. Common uses: stateless strategy/policy implementations, sentinel/empty values, registries, and `Comparator`/`Comparable` helpers — all benefiting from lazy thread-safe init.

code

kotlin · 13 lines
kotlin
interface RetryPolicy { fun shouldRetry(attempt: Int): Boolean }

object NoRetry : RetryPolicy {               // top-level singleton impl
    override fun shouldRetry(attempt: Int) = false
}

class Client {
    object Defaults {                        // nested singleton
        val policy: RetryPolicy = NoRetry
    }
}

val p = Client.Defaults.policy // accessed via class name, no Client instance

go deeper

for a junior

Knows an object can implement an interface and be used as a singleton.

for a middle

Knows it can extend one class and be nested, accessed via the class name.

for a senior

Explains nested-object independence from outer instance, the no-inner/no-subclass rules, and idiomatic uses.

for a principal

Chooses singleton-object designs (sentinels, stateless strategies) deliberately and distinguishes them cleanly from companions and object expressions.

## Capabilities of an object declaration ### Implements interfaces An object can satisfy an interface, giving you a singleton implementation with no boilerplate: ```kotlin val byLength = object : Comparator<String> { /* anonymous */ } // but as a *named singleton*: object LengthComparator : Comparator<String> { override fun compare(a: String, b: String) = a.length - b.length } listOf("bb", "a").sortedWith(LengthComparator) ``` ### Extends one open class It can extend a single open class (Kotlin is single-inheritance for classes): ```kotlin open class BaseHandler { open fun handle() {} } object DefaultHandler : BaseHandler() ``` ### What it CANNOT do - **No constructor / no parameters** — there is one fixed instance. - **Cannot be subclassed / cannot be `open`** as an object — there are no varying instances. - It is effectively final. ## Placement ### Top-level Most objects sit at file top level: `object AppConfig { ... }`. ### Nested in a class An object can be declared inside a class and is reached through the class name: ```kotlin class Repository { object Defaults { // nested object declaration const val PAGE_SIZE = 20 } } val n = Repository.Defaults.PAGE_SIZE ``` Key point: a **nested object is independent of any `Repository` instance** — it is one global singleton, *not* tied to an outer object. (This is unlike an `inner class`, which holds a reference to its enclosing instance; objects cannot be `inner`.) ### Visibility scoping Objects honor visibility modifiers: `private object`, `internal object`, etc., to limit who can see the singleton. ## Typical use cases - **Stateless strategy/policy:** a singleton implementing a `Strategy` interface. - **Sentinel / empty value:** `object EmptyResult : Result`. - **Comparators / orderings.** - **Registries** of immutable data. - **No-op implementations** of a callback interface. All inherit the lazy, thread-safe, exactly-once initialization of object declarations. ## Note on the boundary This leaf is the *named singleton* `object Name`. Two related forms are out of scope here: `companion object` (a singleton tied to a class for factory/static-like members) and *object expressions* (`object : T { }`, anonymous, possibly many instances). They share the keyword but serve different roles. ## Keywords/APIs to name `object`, interface implementation via `: Interface`, single-class inheritance `: OpenClass()`, `private`/`internal object`, contrast with `inner class`, and `Comparator`/`Comparable`.

  • Can an object declaration be `inner`?
    No. `inner` requires a reference to an enclosing instance; an object is a single global instance and has no enclosing-instance link.
  • Can you subclass an `object`?
    No. It is effectively final — there's exactly one instance, so there's nothing to vary via subclassing.

saying these in an interview costs you the question

  • Saying a nested object is tied to / scoped per outer instance
  • Claiming an object can be `inner` or `open`/subclassed
  • Thinking an object can extend multiple classes
  • Conflating the named `object` with companion object or object expression

context