Chapter 3. Enumerated Types
3.1 Creating an Enum
More often than not, you'll only need the basic enum functionality:

 public enum Grade
public enum Grade  { A, B, C, D, F, INCOMPLETE };
{ A, B, C, D, F, INCOMPLETE };The convention is to use all capital letters for enumerated type identifiers.
"Grade" is used just like anyother Java type:

 public class Student
public class Student  {
{
 private String firstName;
    private String firstName;

 private String lastName;
    private String lastName;

 private Grade grade;
    private Grade grade;


 public Student(String firstName, String lastName)
    public Student(String firstName, String lastName)  {
{
 this.firstName = firstName;
        this.firstName = firstName;
 this.lastName = lastName;
        this.lastName = lastName;
 }
    }


 public void assignGrade(Grade grade)
    public void assignGrade(Grade grade)  {
{
 this.grade = grade;
        this.grade = grade;
 }
    }


 public Grade getGrade()
    public Grade getGrade()  {
{
 return grade;
        return grade;
 }
    }

 }
}Pretty basic, isn't it? The final piece is actually using this code in conjunction with the enum, as shown here:

 public void testGradeAssignment(PrintStream out) throws IOException
    public void testGradeAssignment(PrintStream out) throws IOException  {
{
 Student student1 = new Student("Brett", "McLaughlin");
        Student student1 = new Student("Brett", "McLaughlin");
 Student student2 = new Student("Ben", "Rochester");
        Student student2 = new Student("Ben", "Rochester");
 Student student3 = new Student("Dennis", "Erwin");
        Student student3 = new Student("Dennis", "Erwin");
 student1.assignGrade(Grade.B);
        student1.assignGrade(Grade.B);
 student2.assignGrade(Grade.INCOMPLETE);
        student2.assignGrade(Grade.INCOMPLETE);
 student3.assignGrade(Grade.A);
        student3.assignGrade(Grade.A);
 }
    }
Enums extend java.lang.Enum 
Enumerated types aren't integers 
Enums have no public constructor 
Enum values are public, static, and final 
Enum values can be compared with == or equals( )
Enums implements java.lang.Comparable
Enums override toString( )
Enums provide a valueOf( ) method 
Enums define a final instance method named ordinal( )
Enums define a values( ) method
3.2 Declaring Enums Inline

 public class Downloader
public class Downloader  {
{

 public enum DownloadStatus
    public enum DownloadStatus  {
{
 INITIALIZING, IN_PROGRESS, COMPLETE
        INITIALIZING, IN_PROGRESS, COMPLETE
 };
    };
 // Class body
    // Class body
 }
}

Nested enums are implicitly 
static.3.3 Iterating Over Enums
Invoking the 
values( ) method on an enum returns an array of all the values in the type:

 public void listGradeValues(PrintStream out) throws IOException
    public void listGradeValues(PrintStream out) throws IOException  {
{
 Grade[] gradeValues = Grade.values();
        Grade[] gradeValues = Grade.values();

 for (Grade g : Grade.values())
        for (Grade g : Grade.values())  {
{
 out.println("Allowed value: '" + g + "'");
            out.println("Allowed value: '" + g + "'");
 }
        }
 }
    }
Prior to Java 1.4, 
switch only worked with int, short, char, and byte values. However, since enums have a finite set of values, Tiger adds 
switch support for them:

 public void testSwitchStatement(PrintStream out) throws IOException
    public void testSwitchStatement(PrintStream out) throws IOException  {
{
 StringBuffer outputText = new StringBuffer(student1.getFullName());
        StringBuffer outputText = new StringBuffer(student1.getFullName());

 switch (student1.getGrade())
        switch (student1.getGrade())  {
{
 case A:
        case A:
 outputText.append(" excelled with a grade of A");
            outputText.append(" excelled with a grade of A");
 break;
            break;
 case B: // fall through to C
        case B: // fall through to C
 case C:
        case C:
 outputText.append(" passed with a grade of ")
            outputText.append(" passed with a grade of ")
 .append(student1.getGrade().toString());
            .append(student1.getGrade().toString());
 break;
            break;
 case D: // fall through to F
        case D: // fall through to F
 case F:
        case F:
 outputText.append(" failed with a grade of ")
            outputText.append(" failed with a grade of ")
 .append(student1.getGrade().toString());
            .append(student1.getGrade().toString());
 break;
            break;
 case INCOMPLETE:
        case INCOMPLETE:
 outputText.append(" did not complete the class.");
            outputText.append(" did not complete the class.");
 break;
            break;
 default:
        default:
 outputText.append(" has a grade of ")
            outputText.append(" has a grade of ")
 .append(student1.getGrade().toString());
            .append(student1.getGrade().toString());
 }
        }
 out.println(outputText.toString());
        out.println(outputText.toString());
 }
    }Tiger simply 
requires that you not preface each enumerated type with the enum class name. In fact, it's a compilation error if you do!
3.5 Maps of EnumsYou'll need to use the 
java.util.EnumMap class to accomplish this, which is a new collection type just perfect for the job. First, you need to define the enum you want to use for a keyset:

 public enum AntStatus
    public enum AntStatus  {
{
 INITIALIZING,
        INITIALIZING,
 COMPILING,
        COMPILING,
 COPYING,
        COPYING,
 JARRING,
        JARRING,
 ZIPPING,
        ZIPPING,
 DONE,
        DONE,
 ERROR
        ERROR
 }
    }You can now create a
 new 
EnumMap, and pass the 
EnumMap the Class object for the enum used for the keyset:

 public void testEnumMap(PrintStream out) throws IOException
    public void testEnumMap(PrintStream out) throws IOException  {
{
 // Create a map with the key and a String message
        // Create a map with the key and a String message
 EnumMap<AntStatus, String> antMessages = new EnumMap<AntStatus, String>(
        EnumMap<AntStatus, String> antMessages = new EnumMap<AntStatus, String>(
 AntStatus.class);
                AntStatus.class);
 // Initialize the map
        // Initialize the map
 antMessages.put(AntStatus.INITIALIZING, "Initializing Ant");
        antMessages.put(AntStatus.INITIALIZING, "Initializing Ant");
 antMessages.put(AntStatus.COMPILING, "Compiling Java classes");
        antMessages.put(AntStatus.COMPILING, "Compiling Java classes");
 antMessages.put(AntStatus.COPYING, "Copying files");
        antMessages.put(AntStatus.COPYING, "Copying files");
 antMessages.put(AntStatus.JARRING, "JARring up files");
        antMessages.put(AntStatus.JARRING, "JARring up files");
 antMessages.put(AntStatus.ZIPPING, "ZIPping up files");
        antMessages.put(AntStatus.ZIPPING, "ZIPping up files");
 antMessages.put(AntStatus.DONE, "Build complete.");
        antMessages.put(AntStatus.DONE, "Build complete.");
 antMessages.put(AntStatus.ERROR, "Error occurred.");
        antMessages.put(AntStatus.ERROR, "Error occurred.");
 // Iterate and print messages
        // Iterate and print messages

 for (AntStatus status : AntStatus.values())
        for (AntStatus status : AntStatus.values())  {
{
 out.println("For status " + status + ", message is: "
            out.println("For status " + status + ", message is: "
 + antMessages.get(status));
                    + antMessages.get(status));
 }
        }
 }
    }
Similar to Maps of Enums, but use 
java.util.EnumSet. Here are the methods of this class you should be concerned with, most of which are factories:
 // Returns a new EnumSet with all elements from the supplied type
       // Returns a new EnumSet with all elements from the supplied type
 public static EnumSet allOf(Class elementType);
       public static EnumSet allOf(Class elementType);

 // Returns a new EnumSet of the same type as the supplied set, but
       // Returns a new EnumSet of the same type as the supplied set, but
 // with all the values not in the supplied set; a mirror image
       // with all the values not in the supplied set; a mirror image
 public static EnumSet complementOf(EnumSet e);
       public static EnumSet complementOf(EnumSet e);

 // Returns a new EnumSet from the provided collection
       // Returns a new EnumSet from the provided collection
 public static EnumSet copyOf(Collection c);
       public static EnumSet copyOf(Collection c);

 // Returns a new EnumSet with no values in it
       // Returns a new EnumSet with no values in it
 public static EnumSet noneOf(Class elementType);
       public static EnumSet noneOf(Class elementType);

 // Various methods to create an EnumSet with the supplied elements in it
       // Various methods to create an EnumSet with the supplied elements in it
 public static EnumSet of(E e[, E e2, E e3, E e4, E e5]);
       public static EnumSet of(E e[, E e2, E e3, E e4, E e5]);

 // Varags version
       // Varags version
 public static EnumSet of(E
       public static EnumSet of(E e);
 e);

 // Creates an EnumSet with a range of values
       // Creates an EnumSet with a range of values
 public static EnumSet range(E from, E to);
       public static EnumSet range(E from, E to);

 // returns a copy of the current set - not a factory method
       // returns a copy of the current set - not a factory method
 public EnumSet clone( );
       public EnumSet clone( );

 public enum GuitarFeatures
    public enum GuitarFeatures  {
{
 ROSEWOOD(0), // back/sides
        ROSEWOOD(0), // back/sides
 MAHOGANY(0), // back/sides
        MAHOGANY(0), // back/sides
 ZIRICOTE(300), // back/sides
        ZIRICOTE(300), // back/sides
 SPRUCE(0), // top
        SPRUCE(0), // top
 CEDAR(0), // top
        CEDAR(0), // top
 AB_ROSETTE(75), // abalone rosette
        AB_ROSETTE(75), // abalone rosette
 AB_TOP_BORDER(400), // abalone top border
        AB_TOP_BORDER(400), // abalone top border
 IL_DIAMONDS(150), // diamond/square inlay
        IL_DIAMONDS(150), // diamond/square inlay
 IL_DOTS(0); // dots inlays
        IL_DOTS(0); // dots inlays


 /** *//** The upcharge for the feature */
        /** *//** The upcharge for the feature */
 private float upcharge;
        private float upcharge;


 GuitarFeatures(float upcharge)
        GuitarFeatures(float upcharge)  {
{
 this.upcharge = upcharge;
            this.upcharge = upcharge;
 }
        }


 public float getUpcharge()
        public float getUpcharge()  {
{
 return upcharge;
            return upcharge;
 }
        }
 }
    }


 public String getDescription()
    public String getDescription()  {
{

 switch (this)
        switch (this)  {
{
 case ROSEWOOD:
        case ROSEWOOD:
 return "Rosewood back and sides";
            return "Rosewood back and sides";
 case MAHOGANY:
        case MAHOGANY:
 return "Mahogany back and sides";
            return "Mahogany back and sides";
 case ZIRICOTE:
        case ZIRICOTE:
 return "Ziricote back and sides";
            return "Ziricote back and sides";
 case SPRUCE:
        case SPRUCE:
 return "Sitka Spruce top";
            return "Sitka Spruce top";
 case CEDAR:
        case CEDAR:
 return "Wester Red Cedar top";
            return "Wester Red Cedar top";
 case AB_ROSETTE:
        case AB_ROSETTE:
 return "Abalone rosette";
            return "Abalone rosette";
 case AB_TOP_BORDER:
        case AB_TOP_BORDER:
 return "Abalone top border";
            return "Abalone top border";
 case IL_DIAMONDS:
        case IL_DIAMONDS:
 return "Diamonds and squares fretboard inlay";
            return "Diamonds and squares fretboard inlay";
 case IL_DOTS:
        case IL_DOTS:
 return "Small dots fretboard inlay";
            return "Small dots fretboard inlay";
 default:
        default:
 return "Unknown feature";
            return "Unknown feature";
 }
        }
 }
    }There are quite a few things here that you'll need to take note of. First, the class now has a constructor that takes in a 
float parameter for the upcharge of each feature. As a result, each enumerated type now passes in a parameter to the constructor.
Then, variables are declared, and methods appear, just like any other class. 
You cannot put your variable declarations before the enumerated values. All declarations must follow the enumerated type declarations.
...limiting access to the enum constructor? Enum constructors are implicitly private, so this is taken care of for you.
3.8 Implemening Interfaces with Enums

 public class Downloader
public class Downloader  {
{

 public interface Features
    public interface Features  {
{

 /** *//** Get the upcharge for this feature */
        /** *//** Get the upcharge for this feature */
 public float getUpcharge();
        public float getUpcharge();


 /** *//** Get the description for this feature */
        /** *//** Get the description for this feature */
 public String getDescription();
        public String getDescription();
 }
    }
 }
}

It's trivial to make 
GuitarFeatures implement this interface, as the methods are already written:
public enum GuitarFeatures implements Features {
3.9 Value-Specific Class Bodies
 // These are the opcodes that our stack machine can execute.
// These are the opcodes that our stack machine can execute.

 enum Opcode
enum Opcode  {
{
 // Push the single operand onto the stack
    // Push the single operand onto the stack

 PUSH(1)
    PUSH(1)  {
{

 public void perform(StackMachine machine, int[] operands)
        public void perform(StackMachine machine, int[] operands)  {
{
 machine.push(operands[0]);
            machine.push(operands[0]);
 }
        }
 }, // Remember to separate enum values with commas
    }, // Remember to separate enum values with commas

 // Add the top two values on the stack and put the result
    // Add the top two values on the stack and put the result

 ADD(0)
    ADD(0)  {
{

 public void perform(StackMachine machine, int[] operands)
        public void perform(StackMachine machine, int[] operands)  {
{
 machine.push(machine.pop() + machine.pop());
            machine.push(machine.pop() + machine.pop());
 }
        }
 },
    },


 /**//* Other opcode values have been omitted for brevity */
    /**//* Other opcode values have been omitted for brevity */

 // Branch if Equal to Zero
    // Branch if Equal to Zero

 BEZ(1)
    BEZ(1)  {
{

 public void perform(StackMachine machine, int[] operands)
        public void perform(StackMachine machine, int[] operands)  {
{
 if (machine.pop() == 0)
            if (machine.pop() == 0)
 machine.setPC(operands[0]);
                machine.setPC(operands[0]);
 }
        }
 }; // Remember the required semicolon after last enum value
    }; // Remember the required semicolon after last enum value

 // This is the constructor for the type.
    // This is the constructor for the type.

 Opcode(int numOperands)
    Opcode(int numOperands)  {
{
 this.numOperands = numOperands;
        this.numOperands = numOperands;
 }
    }

 int numOperands; // how many integer operands does it expect?
    int numOperands; // how many integer operands does it expect?

 // Each opcode constant must implement this abstract method in a
    // Each opcode constant must implement this abstract method in a
 // value-specific class body to perform the operation it represents.
    // value-specific class body to perform the operation it represents.
 public abstract void perform(StackMachine machine, int[] operands);
    public abstract void perform(StackMachine machine, int[] operands);
 }
}...just using a more generic method that determines what to do based on a switch statement? Well, that's a better idea, to be honest. Here's the (much cleaner) way to write OpCode:
 // These are the the opcodes that our stack machine can execute.
// These are the the opcodes that our stack machine can execute.

 abstract static enum Opcode
abstract static enum Opcode  {
{
 PUSH(1),
    PUSH(1),
 ADD(0),
    ADD(0),
 BEZ(1); // Remember the required semicolon after last enum value
    BEZ(1); // Remember the required semicolon after last enum value

 int numOperands;
    int numOperands;


 Opcode(int numOperands)
    Opcode(int numOperands)  {
{
 this.numOperands = numOperands;
        this.numOperands = numOperands;
 }
    }


 public void perform(StackMachine machine, int[] operands)
    public void perform(StackMachine machine, int[] operands)  {
{

 switch (this)
        switch (this)  {
{
 case PUSH:
        case PUSH:
 machine.push(operands[0]);
            machine.push(operands[0]);
 break;
            break;
 case ADD:
        case ADD:
 machine.push(machine.pop() + machine.pop());
            machine.push(machine.pop() + machine.pop());
 break;
            break;
 case BEZ:
        case BEZ:
 if (machine.pop() == 0)
            if (machine.pop() == 0)
 machine.setPC(operands[0]);
                machine.setPC(operands[0]);
 break;
            break;
 default:
        default:
 throw new AssertionError();
            throw new AssertionError();
 }
        }
 }
    }
 }
}
You couldn't menually define your own enum—at least, not in Tiger. While this is very much an accessible class, and is indeed the base class of all enumerated types in Tiger, the compiler won't let you extend it, as following:
 // Attempting to compile this class give you error
// Attempting to compile this class give you error

 public class ExtendedEnum extends Enum
public class ExtendedEnum extends Enum  {
{

 }
}Here's another one of those pesky, "You don't" labs. Tiger does not allow extension of an enum. For example:
// Attempting to compile this class give you error
public enum CollegeGrade extends Grade { DROP_PASSING, DROP_FAILING }
In theory, this would take the values 
Grade.A, 
Grade.B, and so forth, and add to them two new values, 
CollegeGrade.DROP_PASSING and 
CollegeGrade.DROP_FAILING. However, you'll get compilation errors if you try this.