4.2 Enumerations: Constants, Constructors, Methods, and Custom Bodies
Key Takeaways
Enum types implicitly extend
java.lang.Enum<E>and are implicitly final, or implicitly sealed when a constant declares a class body, so no outside class can extend them while they can still implement interfaces.Enum constructors are implicitly private, executed once per constant during enum class initialization, and can never be invoked via new or reflection.
Constants must be declared first before any fields or methods; a terminating semicolon is mandatory only if additional members or constant bodies are present.
Constant-specific class bodies allow individual constants to override methods or implement abstract methods declared in the enum header.
Standard enum methods include values() (which returns a defensive copy array), valueOf(String), name(), and ordinal(); name() and ordinal() are final and cannot be overridden.
Enumerations: Constants, Constructors, Methods, and Custom Bodies
An enumeration (enum) in Java is a specialized reference type representing a fixed set of named constant instances. Far from being simple integer aliases like enums in C or C++, Java enums are full-featured classes that can encapsulate fields, constructors, business methods, and constant-specific logic. The Oracle 1Z0-829 exam tests the precise lifecycle, constructor semantics, structural constraints, and polymorphism mechanics unique to enum types.
1. Enum Declaration and Class Architecture
An enum is defined using the enum keyword. Behind the scenes, the compiler transforms an enum into a class with specific architectural properties:
public enum Direction {
NORTH, SOUTH, EAST, WEST
}
Compiler-Generated Properties of Enums
- Implicit Superclass: Every enum implicitly extends
java.lang.Enum<E>. Because Java enforces single class inheritance, an enum cannot extend any other class (enum Day extends Calendarfails compilation). - Implicit Modifiers: An enum is implicitly
finalunless at least one constant has a class body, in which case Java 17 makes it implicitlysealed(permitting only those constant bodies). Writingabstractorfinalon an enum declaration yourself is a compile error. In every case, an enum cannot be subclassed by an external class. - Interface Implementation: Although an enum cannot extend any class, it can implement one or more interfaces (
enum Direction implements Navigable, Serializable).
Semicolon and Member Ordering Rules
- Order of Members: The enum constants must be declared first, before any instance fields, static variables, constructors, or methods.
- Semicolon Usage:
- If the enum contains only constants and no other members, the trailing semicolon is completely optional:
enum Status { OPEN, CLOSED } // Valid enum Status { OPEN, CLOSED; } // Also valid - If the enum defines any additional members (fields, constructors, methods) or if constants define constant-specific class bodies, a semicolon after the constant list is strictly mandatory:
enum Status { OPEN, CLOSED; // Semicolon required here! private final int code = 1; }
- If the enum contains only constants and no other members, the trailing semicolon is completely optional:
Warning
Placing a field or method before the enum constants (e.g., private int id; OPEN, CLOSED;) is a compile-time error: the constant list must be the first thing in the enum body.
2. Enum Constructors and Initialization Lifecycle
Enums can declare constructors to initialize fields associated with each constant.
public enum Currency {
USD(1.0), EUR(1.1), JPY(0.007);
private final double exchangeRate;
Currency(double rate) { // Implicitly private
this.exchangeRate = rate;
}
public double getExchangeRate() { return exchangeRate; }
}
Constructor Rules and Modifiers
- Access Modifier: Enum constructors are implicitly private. The only permitted explicit modifier is
private. Declaring an enum constructor aspublicorprotectedcauses a compilation error:modifier public/protected not allowed here. - Cannot Use
new: Enum instances are created exclusively by the JVM when the enum type is initialized. Directly callingnew Currency(1.0)is a compile-time error:enum types may not be instantiated. - Reflection Safety: Attempting to instantiate an enum via reflection (
Constructor.newInstance()) throws anIllegalArgumentException: Cannot reflectively create enum objects. Enums are fundamentally protected against multiple instantiation.
Execution Lifecycle Order
When an enum class is first referenced (e.g., accessing any constant or static method), the JVM initializes the enum. During this initialization, constructors execute for every declared constant in order of declaration before any static members or main method statements execute.
enum Signal {
RED("Stop"), YELLOW("Caution"), GREEN("Go");
Signal(String action) {
System.out.print(action + " ");
}
}
public class SignalTest {
public static void main(String[] args) {
System.out.print("Start: ");
Signal s = Signal.RED;
}
}
Output: Start: Stop Caution Go
Referencing Signal.RED triggers the initialization of the entire Signal class, executing the constructor for RED, then YELLOW, and then GREEN sequentially.
3. Constant-Specific Class Bodies and Abstract Methods
Java enums support constant-specific class bodies, allowing each constant to provide distinct implementations of methods.
Overriding Concrete Methods
public enum Operation {
PLUS {
@Override
public double apply(double x, double y) { return x + y; }
},
MINUS {
@Override
public double apply(double x, double y) { return x - y; }
},
MULTIPLY; // Inherits default apply
public double apply(double x, double y) {
return 0.0;
}
}
Abstract Methods in Enums
An enum can declare an abstract method. If an enum defines an abstract method:
- The enum class itself is not explicitly marked
abstract(the compiler handles this implicitly). - Every constant MUST implement the abstract method in its constant-specific class body. If even one constant fails to implement it, compilation fails.
public enum Calculation {
ADD {
public int compute(int a, int b) { return a + b; }
},
SUBTRACT {
public int compute(int a, int b) { return a - b; }
}; // Both constants implement compute
public abstract int compute(int a, int b); // Abstract method declaration
}
Under the hood, each constant with a class body compiles to an anonymous subclass extending the outer enum class.
4. Standard Enum Methods
Every enum inherits from java.lang.Enum<E> and receives synthetic methods generated by the compiler.
| Method | Return Type | Description | Overridable? |
|---|---|---|---|
values() | E[] | Returns a newly cloned array containing all constants in order of declaration | Synthetic (No) |
valueOf(String name) | E | Returns the constant with the matching name. Throws IllegalArgumentException if not found | Synthetic (No) |
name() | String | Returns the exact declared name of the constant | final (No) |
ordinal() | int | Returns the zero-based position of the constant in the declaration list | final (No) |
toString() | String | Returns name() by default, but can be overridden for user-friendly output | Yes |
compareTo(E o) | int | Compares constants based on their declaration ordinal() order | final (No) |
equals(Object o) | boolean | Compares reference identity (this == o) | final (No) |
Key Caveats for the Exam
values()creates a defensive copy: Each call toEnum.values()allocates a brand-new array. Mutating the returned array (values[0] = null;) does not corrupt the internal enum constants.name()vs.toString():name()isfinaland guaranteed to return the exact identifier declared in source code.toString()can be overridden to return arbitrary strings.ordinal()Fragility: Avoid usingordinal()for business logic or persistence, as reordering or inserting constants changes the ordinal values.
5. Enums in Switch Statements and Expressions
Enums integrate seamlessly with both traditional switch statements and modern Java 17 switch expressions.
The Unqualified Name Rule in Switch Labels
When switching over an enum variable, the case labels must use the unqualified simple name of the constant. Qualifying the constant with the enum class name causes a compilation error:
Direction dir = Direction.NORTH;
switch (dir) {
case NORTH -> System.out.println("Heading North"); // COMPILES: Unqualified name
// case Direction.SOUTH -> System.out.println("South"); // COMPILE ERROR: an enum switch case label must be the unqualified name of an enumeration constant
default -> System.out.println("Other");
}
Exhaustiveness in Switch Expressions
In Java 17 switch expressions, if every constant of the enum is explicitly handled, the default clause can be omitted entirely:
String action = switch (dir) {
case NORTH -> "Up";
case SOUTH -> "Down";
case EAST -> "Right";
case WEST -> "Left";
}; // Fully exhaustive: no default branch needed!
If any constant is left unhandled and no default branch exists, the compiler flags an error: the switch expression does not cover all possible input values.
Consider the following program:
enum SpeedLimit {
CITY(30), HIGHWAY(65), AUTOBAHN(0);
SpeedLimit(int limit) {
System.out.print(limit + " ");
}
}
public class RoadTest {
public static void main(String[] args) {
System.out.print("Drive:");
SpeedLimit sp = SpeedLimit.AUTOBAHN;
System.out.print(":" + sp.name());
}
}
What does this program output when executed?
Drive:0:AUTOBAHN
30 65 0 Drive::AUTOBAHN
Drive:AUTOBAHN:0
Drive:30 65 0 :AUTOBAHN
Examine the following code snippet:
enum TrafficMode { DRIVE, PARK }
public class VehicleController {
public void control(TrafficMode mode) {
switch (mode) {
case TrafficMode.DRIVE:
System.out.println("Moving");
break;
case PARK:
System.out.println("Stationary");
break;
}
}
}
What is the result of attempting to compile this class?
The class compiles successfully and outputs the state based on the provided mode.
Compilation fails because mode cannot be used as an argument to a switch statement without calling ordinal().
Compilation fails because the switch statement does not include a default case.
Compilation fails because case labels for enum switches must be unqualified constant names.
Given the following enum definition:
public enum Protocol {
TCP {
public int getDefaultPort() { return 80; }
},
UDP;
public abstract int getDefaultPort();
}
What is the compilation result for Protocol?
Compilation fails because constant UDP does not implement the abstract method getDefaultPort().
Protocol compiles successfully because UDP inherits 0 as the default port.
Compilation fails because enum classes cannot declare abstract methods.
Compilation fails because TCP cannot define a public method in a constant-specific class body.
Sections you finish are checked off in the contents.