skip to content

Kotlin enums (like Java enums) carry a synthetic `$VALUES` field and `values()`/`valueOf()` methods. Explain what `$VALUES` is, how `entries` differs from `values()`, and why this matters at the Java boundary and in reflection.

level: seniorimportance: nice to knowfreq 18%

answer

  1. $VALUES = static array of all constants, decl order
  2. values() returns a clone() each call (allocation)
  3. entries (1.9+) = cached immutable List, no copy
  4. Java sees getEntries(); values()/valueOf() stay
  5. $VALUES is synthetic -> reflection skips it

basics

~20 s

$VALUES is a hidden static array holding every enum constant once. values() returns a defensive copy of it each call; valueOf() looks a name up in it. Kotlin's newer entries property returns a cached immutable list instead, avoiding the per-call copy.

solid answer

~40 s

Every JVM enum (Kotlin or Java) gets a synthetic `private static final ENUM[] $VALUES` built in the class's static initializer, containing each constant in declaration order. The compiler-generated `values()` returns `$VALUES.clone()` — a fresh defensive copy on every call so callers can't mutate the canonical set, which is a hidden allocation cost in hot loops. `valueOf(String)` resolves a name against this set (throwing IllegalArgumentException on miss). Kotlin 1.9+ adds the `entries` property (`EnumEntries<T>`, an immutable `List`) that is **cached** — no per-call copy — and is the preferred replacement for `values()` in Kotlin code. `$VALUES` is synthetic and shows up in reflection; tools enumerating fields must skip it. From Java you still call `MyEnum.values()`/`valueOf()`; `entries` is exposed as `getEntries()`.

code

kotlin · 12 lines
kotlin
enum class Level { LOW, MID, HIGH }

// Preferred in Kotlin 1.9+: cached, no per-call clone
fun maxLevel() = Level.entries.maxBy { it.ordinal }

// values() allocates a fresh array each call:
fun countOld() = Level.values().size

// Java still uses:
//   Level[] xs = Level.values();
//   Level h = Level.valueOf("HIGH");
//   List<Level> es = Level.getEntries();

go deeper

for a junior

Knows enums have values()/valueOf() and a hidden constant array.

for a middle

Explains $VALUES is cloned by values() and that entries is the newer cached alternative.

for a senior

Details the per-call allocation cost, EnumEntries immutability, Java getEntries() exposure, and reflection skipping synthetic fields.

for a principal

Sets codebase policy (prefer entries), reasons about allocation in hot paths, migration from values(), and reflection-tooling implications.

## The synthetic enum machinery The JVM treats `enum` specially. For any enum the compiler generates, in the static initializer: - each constant as a `public static final` field, - a `private static final MyEnum[] $VALUES` array holding all constants in **declaration order**, - `public static MyEnum[] values()` returning `$VALUES.clone()`, - `public static MyEnum valueOf(String name)`. ```kotlin enum class Suit { HEARTS, SPADES, CLUBS, DIAMONDS } ``` Conceptually: ```java public static final Suit HEARTS = new Suit("HEARTS", 0); // ... private static final Suit[] $VALUES = $values(); // {HEARTS, SPADES, CLUBS, DIAMONDS} public static Suit[] values() { return $VALUES.clone(); } public static Suit valueOf(String s) { return Enum.valueOf(Suit.class, s); } ``` ## Why `values()` clones every call Arrays are mutable. If `values()` returned the shared `$VALUES` directly, a caller could overwrite an element and corrupt the canonical set for everyone. So each call returns a **defensive copy** via `clone()`. That's a real **allocation on every invocation** — wasteful when you iterate constants in a tight loop or call it repeatedly. ## `entries` vs `values()` Kotlin **1.9** stabilized the `entries` property: ```kotlin val all = Suit.entries // EnumEntries<Suit> : List<Suit>, immutable, cached for (s in Suit.entries) { /* no per-iteration copy */ } ``` - `entries` returns a **single cached, immutable** `EnumEntries<T>` (a `List`), so no defensive copy and no repeated allocation. - It's the **recommended** replacement for `values()` in new Kotlin code. - From **Java** it's accessed as `Suit.getEntries()`; Java still has and often uses `values()`. ## Boundary & reflection notes - `$VALUES` is **synthetic**; `Class.getDeclaredFields()` will list it, so serializers/DI/coverage tools must skip synthetic fields. - `values()`/`valueOf()` remain the Java-facing API; don't try to read `$VALUES` reflectively as stable API. - `valueOf` throws `IllegalArgumentException` for unknown names — guard with a lookup or `entries.find { it.name == s }` / Kotlin's `enumValueOf` / `runCatching`. ## Quick guidance - New Kotlin loops over constants -> use `entries`. - Interop / Java callers -> `values()` / `valueOf()` still work. - Treat `$VALUES` as an invisible implementation detail.

  • Why is calling values() inside a hot loop a smell?
    Each call clones $VALUES, allocating a new array; hoist it out or use the cached entries property instead.
  • How is entries exposed to Java callers?
    As a getter, MyEnum.getEntries(), returning an EnumEntries/List; Java code can use it or stick with values().

$VALUES is the master guest list locked in the office; values() photocopies it for anyone who asks (so they can't scribble on the original), while entries hands out one shared read-only copy that everyone reuses.

saying these in an interview costs you the question

  • Claiming values() returns the shared array (it clones)
  • Saying entries and values() are identical with no caching difference
  • Not knowing entries arrived in Kotlin 1.9
  • Thinking $VALUES is a stable, callable API
  • Forgetting valueOf throws IllegalArgumentException on miss

context