How do enums guarantee one instance per constant, and why does that make the single-element enum a robust singleton?
answer
- Constants built once under the thread-safe class-init lock
- new on an enum is a compile error; constructor implicitly private
- Single-element enum = Effective Java's best singleton
- Reflection blocked (newInstance throws), serialization resolves to the constant
- Trade-off: eager init, cannot extend a class
basics
~20 sThe JVM creates each enum constant exactly once during thread-safe class initialization, and the language forbids new instances. A single-constant enum is therefore a singleton that is automatically thread-safe and resistant to reflection and serialization attacks.
solid answer
~50 sEnum constants are initialized as part of the enum class's static initialization, which the JVM guarantees happens **exactly once and in a thread-safe way** under the class-initialization lock — so there is no double-checked-locking or volatile needed. The language also bans `new` on an enum and makes the constructor implicitly private, so no extra instances can be created. Effective Java therefore recommends a **single-element enum as the best singleton**: `enum Service { INSTANCE; ... }`. It is concise, thread-safe by construction, and — crucially — the JVM and serialization machinery special-case enums so that reflection cannot call the constructor (Constructor.newInstance throws for enums) and deserialization always returns the existing constant rather than fabricating a new object (no readResolve needed). Traditional singleton implementations must hand-defend against all three of those attacks; the enum gets them for free. The minor limitations are that an enum singleton cannot extend a class (it already extends Enum) and is eagerly initialized on class load.
code
java · 12 linespublic enum Config {
INSTANCE; // the single instance
private final Properties props = load();
private static Properties load() { /* read file once */ return new Properties(); }
public String get(String key) { return props.getProperty(key); }
}
// Thread-safe, reflection-proof, serialization-proof; no locking, no readResolve:
String url = Config.INSTANCE.get("db.url");go deeper
Knows each enum constant exists exactly once and that an enum can be used as a singleton.
Explains that constants are created during thread-safe class initialization and that new is forbidden, so a one-constant enum is a thread-safe singleton.
Articulates why the enum singleton beats hand-written ones: free thread safety plus immunity to reflection, serialization, and cloning attacks, and names the trade-offs.
Decides singleton strategy at the architecture level: when an enum singleton is appropriate vs DI-managed single instances, lazy-holder for expensive resources, and the testability/coupling implications of global singletons.
## The guarantee: one instance per constant When an enum class is first used, the JVM **initializes** it: it runs the static setup that constructs **each constant exactly once**, in declaration order. The Java Language Specification guarantees class initialization is **serialized** — the JVM holds a per-class initialization lock, so even if many threads touch the enum simultaneously, the constants are built once and every thread sees the same fully-constructed objects. This is *lazy* (on first use) yet *thread-safe* with **no programmer effort** — no `synchronized`, no `volatile`, no double-checked locking. Combined with the **implicitly private constructor** and the rule that **`new` on an enum is a compile error**, this means the set of instances is exactly the declared constants — no more can ever exist. ## The single-element enum singleton A **singleton** is a class with exactly one instance, globally accessible. Effective Java (Item 3) states the **best way to implement a singleton is a single-element enum**: ```java public enum DatabasePool { INSTANCE; private final List<Connection> pool = ...; public Connection borrow() { ... } } // use: DatabasePool.INSTANCE.borrow(); ``` Why it is superior to the classic approaches (`private static final` field, lazy holder, double-checked locking): ### 1. Thread safety for free The instance is created during class initialization, which is already thread-safe — you do not write any locking. ### 2. Reflection-proof A normal singleton with a private constructor can be defeated by reflection: `constructor.setAccessible(true); constructor.newInstance();` creates a second instance. For enums the JVM **special-cases reflection**: `Constructor.newInstance()` on an enum constructor throws `IllegalArgumentException("Cannot reflectively create enum objects")`. So the attack is impossible. ### 3. Serialization-proof If a normal singleton implements `Serializable`, naive deserialization creates a **new** instance each time, breaking the singleton; you must add a `readResolve()` method returning the canonical instance, and mark fields transient. Enums are serialized **specially — by name only** — and deserialization resolves back to the **existing constant** via `Enum.valueOf`. You get correct serialization with **zero extra code**. ### 4. Cloning-proof `Enum` makes `clone()` `final` and it throws, so you cannot duplicate a constant via cloning either. ## Limitations / trade-offs - **No class inheritance**: the enum already extends `java.lang.Enum`, so a singleton that must extend some base class cannot be an enum (it can still implement interfaces — often enough). - **Eager-ish initialization**: the constant is built when the enum class loads; for a singleton this is usually fine, but if you need strictly lazy creation of an expensive resource tied to first *method* call, the initialization-on-demand holder idiom may fit better. - **Testability**: like any global singleton, an enum singleton can complicate dependency injection and mocking; that is a property of the singleton pattern, not the enum. ## Summary The JVM constructs enum constants once under the thread-safe class-init lock and forbids new instances, so a one-constant enum is a singleton that is inherently thread-safe and immune to the reflection, serialization, and cloning attacks that plague hand-written singletons — at the cost of eager init and no class inheritance.
- Why does an enum singleton survive serialization without a readResolve() method?Enums are serialized specially: only the constant's name is written, and on deserialization the runtime calls Enum.valueOf to resolve back to the existing constant rather than constructing a new object. The usual problem where a Serializable singleton yields a fresh instance — requiring a hand-written readResolve — simply does not arise for enums.
- What is the main reason you might NOT use an enum singleton?An enum already extends java.lang.Enum, so it cannot extend another class — if your singleton must inherit from a specific base class you cannot use an enum (it can still implement interfaces). Eager initialization on class load and the general testability/DI drawbacks of any global singleton are secondary considerations.
saying these in an interview costs you the question
- Adding double-checked locking or volatile to an enum singleton (redundant)
- Writing readResolve() for an enum singleton (the JVM already handles it)
- Claiming reflection can create a second enum instance (it throws)
- Believing an enum singleton can extend a base class