Section 3.5. Enumerated Types


3.5. Enumerated Types

Java 5 includes support for enumerated types. Here is a simple example:

 enum Season { WINTER, SPRING, SUMMER, FALL } 

Each enumerated type declaration can be expanded into a corresponding class in a stylized way. The corresponding class is designed so that it has exactly one instance for each of the enumerated constants, bound to a suitable static final variable. For example, the enum declaration above expands into a class called Season. Exactly four instances of this class exist, bound to four static final variables with the names WINTER, SPRING, SUMMER, and FALL.

Each class that corresponds to an enumerated type is a subclass of java.lang.Enum. Its definition in the Java documentation begins like this:

 class Enum<E extends Enum<E>> 

You may find this frightening at first sightboth of us certainly did! But don't panic. Actually, we've already seen something similar. The worrying phrase E extends Enum<E> is a lot like the phrase T extends Comparable<T> that we encountered in the definition of max (see Section 3.2), and we'll see that they appear for related reasons.

To understand what's going on, we need to take a look at the code. Example 3.4 shows the base class Enum and Example 3.5 shows the class Season that corresponds to the enumerated type declaration above. (The code for Enum follows the source in the Java library, but we have simplified a few points.)

Example 3-4. Base class for enumerated types

 public abstract class Enum<E extends Enum<E>> implements Comparable<E> {   private final String name;   private final int ordinal;   protected Enum(String name, int ordinal) {     this.name = name; this.ordinal = ordinal;   }   public final String name() { return name; }   public final int ordinal() { return ordinal; }   public String toString() { return name; }   public final int compareTo(E o) {     return ordinal - o.ordinal;   } } 

Example 3-5. Class corresponding to an enumerated type

 // corresponds to // enum Season { WINTER, SPRING, SUMMER, FALL } final class Season extends Enum<Season> {   private Season(String name, int ordinal) { super(name,ordinal); }   public static final Season WINTER = new Season("WINTER",0);   public static final Season SPRING = new Season("SPRING",1);   public static final Season SUMMER = new Season("SUMMER",2);   public static final Season FALL   = new Season("FALL",3);   private static final Season[] VALUES = { WINTER, SPRING, SUMMER, FALL };   public static Season[] values() { return VALUES.clone(); }   public static Season valueOf(String name) {     for (Season e : VALUES) if (e.name().equals(name)) return e;     throw new IllegalArgumentException();   } } 

Here is the first line of the declaration for the Enum class:

 public abstract class Enum<E extends Enum<E>> implements Comparable<E> 

And here is the first line of the declaration for the Season class:

 class Season extends Enum<Season> 

Matching things up, we can begin to see how this works. The type variable E stands for the subclass of Enum that implements a particular enumerated type, such as Season. Every E must satisfy:

 E extends Enum<E> 

So we can take E to be Season, since:

 Season extends Enum<Season> 

Furthermore, the declaration of Enum tells us that:

 Enum<E> implements Comparable<E> 

So it follows that:

 Enum<Season> implements Comparable<Season> 

Hence, we are allowed to compare two values of type Season with each other, but we cannot compare a value of type Season with a value of any other type.

Without the type variable, the declaration of the Enum class would begin like this:

 class Enum implements Comparable<Enum> 

And the declaration for the Season class would begin like this:

 class Season extends Enum 

This is simpler, but it is too simple. With this definition, Season would implement Comparable<Enum> rather than Comparable<Season>, which would mean that we could compare a value of type Season with a value of any enumerated type, which is certainly not what we want!

In general, patterns like T extends Comparable<T> and E extends Enum<E> often arise when you want to pin down types precisely. We'll see further examples of this when we look at the Strategy and Subject-Observer design patterns, in Sections 9.4 and 9.5.

The rest of the definition is a straightforward application of the typesafe enum pattern described by Joshua Bloch in Effective Java (Addison-Wesley), which in turn is an instance of the singleton pattern described by Gamma, Helm, Johnson, and Vlissides in Design Patterns (Addison-Wesley).

The base class Enum defines two fields, a string name and an integer ordinal, that are possessed by every instance of an enumerated type; the fields are final because once they are initialized, their value never changes. The constructor for the class is protected, to ensure that it is used only within subclasses of this class. Each enumeration class makes the constructor private, to ensure that it is used only to create the enumerated constants. For instance, the Season class has a private constructor that is invoked exactly four times in order to initialize the final variables WINTER, SPRING, SUMMER, and FALL.

The base class defines accessor methods for the name and ordinal fields. The toString method returns the name, and the compareTo method just returns the difference of the ordinals for the two enumerated values. (Unlike the definition of Integer in Section 3.1, this is safe because there is no possibility of overflow.) Hence, constants have the same ordering as their ordinalsfor example, WINTER precedes SUMMER.

Lastly, there are two static methods in every class that corresponds to an enumerated type. The values method returns an array of all the constants of the type. It returns a (shallow) clone of the internal array. Cloning is vital to ensure that the client cannot alter the internal array. Note that you don't need a cast when calling the clone method, because cloning for arrays now takes advantage of covariant return types (see Section 3.8). The valueOf method takes a string and returns the corresponding constant, found by searching the internal array. It returns an IllegalArgumentException if the string does not name a value of the enumeration.




Java Generics and Collections
Java Generics and Collections
ISBN: 0596527756
EAN: 2147483647
Year: 2006
Pages: 136

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net