Enumerations

Now that we've covered the basics of classes, we can talk in more depth about one of the cool new features in Java 5.0, enumerations. An enumeration is an object type in the Java language that is limited to an explicit set of values. The values have an order, defined by their order of declaration in the code, and have a correspondence with a string name that is the same as their declared name in the source code. We've already seen a couple of examples of enumerations used in place of static identifiers. For example:

 enum Weekday { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }
 // usage
 setDay( Weekday.Sunday );


Let's take a look at what the Java compiler is actually generating for the enum. It is a regular Java class, in this case named Weekday, so we can display it with the javap command like so:

 % javap Weekday
 public final class Weekday extends java.lang.Enum {
 public static final Weekday Sunday;
 public static final Weekday Monday;
 public static final Weekday Tuesday;
 public static final Weekday Wednesday;
 public static final Weekday Thursday;
 public static final Weekday Friday;
 public static final Weekday Saturday;
 public static final Weekday[] values( );
 public static Weekday valueOf(java.lang.String);
 }


Weekday is a subclass of the Enum type with seven static, final, "constant" object references corresponding to our seven enumerated values. Each of the enumerated values is of type Weekday. The Java compiler does not let us extend this class or create any other instances of this type. The only instances of Weekday that will ever exist are the seven enumerated values. This is what gives enumerations their type safety. A method expecting a Weekday can be given one of only seven values. Unlike a numeric constant identifier, no value other than a Weekday will work. As we saw in , enumerations (unlike most objects) can also be used in switch statements with all the same benefits. Because enumerations are static values, they can be imported with the new Java static import, saving us some typing:

 import mypackage.Weekday.*;
 ...
 setDay( Friday );
 setDeadline( Sunday );


We should also mention that enumerations can be declared not only at the "top level" alongside classes but within classes or interfaces as well. In this case, they act just like inner classes (see ).

Enum Values

You can get the ordered list of enum values for a type with the static values( ) method.

 Weekday [] weekdays = Weekday.values( );


The compareTo( ) method of an enum compares an enum value to another value of the same enum type and returns an integer less than zero, zero, or greater than zero, indicating whether the target enum is "less than," "equal to," or "greater than" the order of the reference enum. This doesn't mean much for our Weekdays, but it might be useful for values that have a more numeric meaning or a (noncyclic) scale of some kind. For example:

 Level level = Level.HIGH;
 Level anotherLevel = Level.LOW;
 if ( level.compareTo( anotherLevel ) > 0 ) // true
 doSomething( );


We mentioned that enum values have a string correspondence for their names. You can get the string name of the value (which is exactly the same as it is declared in the source code) with the name( ) method. Going the other direction, you can "look up" any enum value by its class type and string name using the static Enum.valueOf( ) method:

 String mondayString = Weekday.Monday.name( ); // "Monday"
 Weekday mondayWeekday = Enum.valueOf( Weekday.class, "Monday" );


The name( ) value is also used by the toString( ) method of the value, so printing an enum value does what you'd expect.

Customizing Enumerations

We said that the java.lang.Enum type cannot be directly extended and that you can't create new instances of enum types. However, you can add things to the generated enumeration class when it's declared. For example, the enumeration java.util.concurrent.TimeUnit, which has identifiers for time units such as SECONDS, MILLISECONDS, and MICROSECONDS, has a sleep( ) method that interprets its argument in the correct time scale:

 import static java.util.concurrent.TimeUnit.*;
 SECONDS.sleep( 5 ); // sleep 5 seconds


Enumerations can have values with constructors, methods, and fields just like other classes. For the most part, this is straightforward; you just add a semicolon after the enum values and then add your additional class members. Let's add a "fun" value and accessor method to our weekdays:

 public enum Weekday
 {
 Sunday(8), Monday(0), Tuesday(1), Wednesday(2), Thursday(4),
 Friday(6), Saturday(10) ;
 int fun;
 Weekday( int fun ) { this.fun = fun; }
 public int getFun( ) { return fun; }
 }


Here, we've added an instance variable, fun, to the Weekday class, as well as a constructor and accessor method that work with the value. The declaration of our enum values each now accepts the constructor value, much like a constructor call without the new keyword. Note that the semicolon at the end of the values is mandatory. Each Weekday now has a fun attribute. There is an odd special feature of enums that we didn't show. In addition to adding features to the enum class as a whole (as in our example), we can add methods and variables to individual values of the enumeration by giving them a body with curly braces ({}). This is best served by an example:

 enum Cat {
 Himilayan, Siamese, Caleco,
 Persian {
 public void someMethod( ) { ... }
 }
 }


Now, only the Cat.Persian enum value has the method. In this case, the compiler generates a subclass of Cat as an inner class of the Persian type to hold the extra member. (We'll talk about inner classes in .) You could use this to have the Persian member override a method in the base enum class.

Comments