An enum can carry fields and a constructor. How does that interact with ordinal(), name(), and constant-specific behavior?
answer
- Each constant passes args to an implicitly-private constructor
- final fields -> immutable per-constant data (Planet mass/radius)
- name() = source identifier (final); ordinal() = declaration index
- Prefer name()/valueOf over ordinal() for logic & storage
- values() returns all constants in order
basics
~20 sEach constant can pass arguments to a private enum constructor to set its own fields, like Planet(mass, radius). name() returns the constant's identifier text and ordinal() its position. You read fields through getters; ordinal/name come for free.
solid answer
~40 sAn enum can declare instance fields and a constructor; each constant supplies the constructor arguments in parentheses, e.g. `MERCURY(3.3e23, 2.4e6)`. The constructor is implicitly private (you can't call it elsewhere), and it runs once per constant during class initialization, so the per-constant state is effectively immutable if you make the fields final. Separately, every constant gets `name()` (the exact identifier you wrote) and `ordinal()` (its zero-based declaration position) for free from java.lang.Enum. These are distinct from your own fields: prefer name() over a hand-rolled string field, and avoid relying on ordinal() for logic or storage since it shifts if constants are reordered. Constant-specific behavior (bodied constants overriding methods) can combine with fields, so a constant can both hold data and compute differently.
code
java · 13 linesenum Coin {
PENNY(1), NICKEL(5), DIME(10), QUARTER(25);
private final int cents;
Coin(int cents) { this.cents = cents; } // implicitly private
int cents() { return cents; }
}
int v = Coin.QUARTER.cents(); // 25
String n = Coin.QUARTER.name(); // "QUARTER"
int o = Coin.QUARTER.ordinal(); // 3
Coin c = Coin.valueOf("DIME"); // Coin.DIMEgo deeper
Knows constants can pass constructor args to set fields, and that name()/ordinal()/values()/valueOf exist.
Uses final fields for immutable per-constant data and prefers name()/valueOf over ordinal() for persistence.
Explains the implicit-private constructor, per-constant initialization timing, and why ordinal is reserved for EnumSet/EnumMap, not logic.
Sets team conventions around enum persistence (name not ordinal), considers schema evolution, and combines field data with constant-specific behavior cleanly.
## Enums are classes with fixed instances An `enum` is really a class whose instances are the listed constants. Like any class it can have **instance fields**, a **constructor**, and **methods** — the twist is that you can't `new` it; the constants are created for you. ## Per-constant fields via the constructor Give the enum fields and a constructor, then each constant **passes arguments** in parentheses: ```java enum Planet { MERCURY(3.303e23, 2.4397e6), EARTH (5.976e24, 6.37814e6); // each constant calls the constructor private final double mass; // in kilograms private final double radius; // in meters Planet(double mass, double radius) { // implicitly private this.mass = mass; this.radius = radius; } double surfaceGravity() { return 6.67300E-11 * mass / (radius * radius); } } ``` Key points: - The **constructor is implicitly `private`** — you cannot declare it `public`/`protected`, and you can't call it anywhere except via the constant declarations. This is what keeps the instance set closed. - The constructor runs **once per constant**, in declaration order, during the enum's class initialization. Make fields `final` for an effectively immutable constant. - Constants with constructor arguments and constants with method bodies can be combined: `EARTH(5.97e24, 6.37e6) { double greeting() {...} }`. ## name() vs ordinal() vs your fields `java.lang.Enum` gives every constant two free accessors: - **`name()`** returns the **exact identifier** as written in source, e.g. `Planet.EARTH.name()` -> `"EARTH"`. `toString()` defaults to the same but can be overridden; `name()` is `final` and cannot. - **`ordinal()`** returns the **zero-based position** in declaration order: `MERCURY.ordinal()` -> 0, `EARTH.ordinal()` -> 1. These are **separate** from any fields you declare. Guidance: - Don't create your own `String code` field that just duplicates the constant name — use `name()`. - **Avoid `ordinal()` for logic or persistence.** It's documented as existing mainly for `EnumSet`/`EnumMap`; using it in business logic or storing it makes your code brittle, because inserting or reordering constants silently shifts every later ordinal. Store/match on `name()` and convert back with `valueOf("EARTH")`. ## valueOf and values() Two more generated helpers complete the picture: `Planet.valueOf("EARTH")` returns the constant for that name (throws `IllegalArgumentException` if none), and `Planet.values()` returns a fresh array of all constants in declaration order — handy for iteration. ## Putting it together Use the constructor + final fields to attach immutable data to each constant; use `name()`/`valueOf` for stable string identity; reach for constant-specific bodies when each constant must *behave* differently as well. Keep `ordinal()` out of your logic.
- Why can't you make an enum constructor public?Enum constructors are implicitly private so the set of instances stays closed — only the declared constants can invoke it. Declaring it public/protected is a compile error.
- Why prefer name() over ordinal() when storing an enum value?name() is a stable string tied to the identifier, while ordinal() is just a position that changes if you reorder or insert constants — persisting it silently corrupts data.
The enum is a class roster where every student (constant) is pre-enrolled with a fixed ID badge: name() is the name printed on the badge, ordinal() is just their seat number — fine for seating charts, dangerous to use as a permanent identity.
saying these in an interview costs you the question
- Making the enum constructor public or calling it directly.
- Storing or branching on ordinal() in business logic / databases.
- Adding a redundant string field that just mirrors name().
- Assuming values() returns a cached array — it returns a fresh copy each call.