Why can enum constants be compared safely with `==`, and what does it mean that each constant is a singleton?
answer
- each constant constructed once at class load
- every reference = same object
- == and === always agree for enums
- equals/hashCode are final, identity-based
- great for when, map keys, EnumSet/EnumMap
basics
~20 sEach enum constant exists as exactly one object created once at class load. So referencing RED always gives the same instance, and == (which compares value) and === (which compares identity) both reliably tell constants apart.
solid answer
~40 sEach enum constant is a **singleton**: the runtime constructs it exactly once during class initialization and every reference (`Color.RED`) yields that same object. Because of this, structural equality `==` and referential equality `===` give identical results for enums — `Color.RED == Color.RED` and `Color.RED === Color.RED` are both true, and two different constants are never equal. The inherited `equals`/`hashCode` from `kotlin.Enum` are final identity-based implementations, so you cannot (and shouldn't) override them. This singleton nature also makes enums ideal `when`-subjects (exhaustive, identity-cheap), valid map keys (stable hashCode), and safe across `==`. One caveat: the singleton guarantee is per class-loader/JVM; constants serialized and deserialized across processes are matched by `name`, not object identity.
code
kotlin · 6 linesenum class Light { RED, YELLOW, GREEN }
val x = Light.GREEN
val y = Light.valueOf("GREEN")
println(x == y) // true
println(x === y) // true — same singleton instancego deeper
Knows == works to compare enum constants.
Explains that constants are singletons so == and === agree.
Knows equals/hashCode are final identity-based, the cross-process name caveat, and EnumMap/EnumSet benefits.
Designs identity/serialization contracts and chooses enum vs sealed objects based on identity and evolution needs.
## Each constant is a singleton When an enum class is loaded, the JVM constructs **each constant exactly once** and stores it. From then on, every mention of `Color.RED` returns **that same object**: ```kotlin enum class Color { RED, GREEN, BLUE } val a = Color.RED val b = Color.RED println(a === b) // true — identical object ``` There is no way to create another `RED`; the constructor is closed to outside code, so the set of instances is fixed. ## `==` vs `===` for enums - `==` is **structural equality** (calls `equals`). - `===` is **referential equality** (same object identity). For most classes these can differ. For enums they **always agree**, because `kotlin.Enum` provides **final, identity-based** `equals`/`hashCode`: two references are `equals` iff they are the same constant iff they are the same object. ```kotlin Color.RED == Color.RED // true Color.RED === Color.RED // true Color.RED == Color.GREEN // false ``` This is why you can freely use `==` in `when` and `if` over enums without worrying about a broken `equals`. ## You cannot override equals/hashCode Because `kotlin.Enum.equals` and `hashCode` are **final**, the compiler forbids overriding them. That guarantees the identity semantics and keeps enums safe as: - **Map/Set keys** (stable hashCode, fast). - **`when` subjects** (cheap identity dispatch, exhaustiveness). ## Specialized collections The singleton/ordinal structure enables highly efficient `EnumMap`/`EnumSet` (from the Java standard library), backed by arrays indexed by ordinal rather than hashing. ## The cross-process caveat The "single instance" guarantee holds **within one JVM/class-loader**. If you serialize a constant and read it back in another process, you don't get the *same object* — frameworks reconnect it to the local singleton by matching **`name`** (which is exactly why you serialize by name). So reason about identity within a process, and about `name` across process boundaries.
- Can you override equals() on an enum to change comparison?No. kotlin.Enum's equals and hashCode are final identity-based implementations; the compiler rejects overrides.
- Is the singleton guarantee absolute across processes?Within one JVM/class-loader yes. Across processes, deserialization reconnects by name to the local constant; you don't get the same object reference.
- Why are enums good map keys?Stable, identity-based hashCode and a small fixed key space; you can even use the array-backed EnumMap/EnumSet for efficiency.
Like a country's official flag: there's one canonical instance everyone points to, not a fresh copy each time you mention it.
saying these in an interview costs you the question
- Claiming you should use === instead of == for safety (both are fine and equal)
- Trying to override equals/hashCode on an enum
- Thinking each `Color.RED` reference makes a new object
- Assuming object identity survives serialization across processes
- Not recognizing enums as safe, efficient map/set keys