All 15 Enums questions
More in Enums
Advertisement
Back to results for “Design Patterns in Java”
Java › Enums

How does Java implement enums under the hood at the bytecode level (extending java.lang.Enum), and what makes them inherently thread-safe and serialization-safe as singletons?

Advanced

Answer

Every enum implicitly extends java.lang.Enum<T> (making explicit inheritance of another class impossible, since Java lacks multiple inheritance), with each constant compiled as a public static final field initialized exactly once during the enum class's static initialization (a process the JVM itself guarantees is thread-safe and happens exactly once, even under concurrent class loading) -- this JVM-guaranteed single-initialization behavior is precisely what makes enum-based Singletons inherently thread-safe without any explicit synchronization needed; additionally, the JVM's default serialization mechanism for enums deliberately serializes only the constant's name (not its fields), deserializing by looking up the matching constant via valueOf() rather than creating a new instance, which is what makes enum singletons immune to the classic serialization-based Singleton-breaking attack that affects a conventional private-constructor Singleton implementation.
// Decompiled bytecode conceptually resembles:
public abstract class Day extends Enum<Day> {
    public static final Day MONDAY = new Day("MONDAY", 0);
    // ... other constants
    private static final Day[] VALUES = { MONDAY, /* ... */ };

    public static Day[] values() { return VALUES.clone(); }
    public static Day valueOf(String name) { /* looks up by name */ }
}
Real-world example A security-conscious library specifically chooses an enum-based Singleton over the classic private-constructor approach precisely because enum's special JVM-guaranteed serialization behavior (deserializing to the existing constant rather than creating a new instance) closes off a known technique for breaking Singleton uniqueness via crafted serialized data, a vulnerability the classic approach requires extra defensive code to prevent.

Common follow-ups: Why can't an enum extend any other class, given it already implicitly extends java.lang.Enum?;What specific serialization attack does the classic private-constructor Singleton remain vulnerable to that enum-based Singleton avoids?