Chapter: Java The Complete Reference - The Java Language - Enumerations, Autoboxing, and Annotations (Metadata)

| Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail |

Enumerations - Java

Versions of Java prior to JDK 5 lacked one feature that many programmers felt was needed: enumerations. In its simplest form, an enumeration is a list of named constants.

Enumerations

 

Versions of Java prior to JDK 5 lacked one feature that many programmers felt was needed: enumerations. In its simplest form, an enumeration is a list of named constants. Although Java offered other features that provide somewhat similar  functionality, such as final variables, many programmers still missed the conceptual purity of enumerations— especially because enumerations are supported by many other commonly used languages. Beginning with JDK 5, enumerations were added to the Java language, and they are now an integral and widely used part of Java.

 

In their simplest form, Java enumerations appear similar to enumerations in other languages. However, this similarity may be only skin deep because, in Java, an enumeration defines a class type. By making enumerations into classes, the capabilities of the enumeration are greatly expanded. For example, in Java, an enumeration can have constructors, methods, and instance variables. Therefore, although enumerations were several years in the making, Java’s rich implementation made them well worth the wait.

 

Enumeration Fundamentals

 

An enumeration is created using the enum keyword. For example, here is a simple enumeration that lists various apple varieties:

 // An enumeration of apple varieties.

enum Apple {

 

Jonathan, GoldenDel, RedDel, Winesap, Cortland

 

}

The identifiers Jonathan, GoldenDel, and so on, are called enumeration constants. Each is implicitly declared as a public, static final member of Apple. Furthermore, their type is the type of the enumeration in which they are declared, which is Apple in this case. Thus, in the language of Java, these constants are called self-typed, in which “self” refers to the enclosing enumeration.

 

Once you have defined an enumeration, you can create a variable of that type. However, even though enumerations define a class type, you do not instantiate an enum using new. Instead, you declare and use an enumeration variable in much the same way as you do one of the primitive types. For example, this declares ap as a variable of enumeration type Apple:

 

Apple ap;

 

Because ap is of type Apple, the only values that it can be assigned (or can contain) are those defined by the enumeration. For example, this assigns ap the value RedDel:

 

ap = Apple.RedDel;

 

Notice that the symbol RedDel is preceded by Apple.

 

Two enumeration constants can be compared for equality by using the = = relational operator. For example, this statement compares the value in ap with the GoldenDel constant:

 

 

if(ap == Apple.GoldenDel) // ...

 

An enumeration value can also be used to control a switch statement. Of course, all of the case statements must use constants from the same enum as that used by the switch expression. For example, this switch is perfectly valid:

 

// Use an enum to control a switch statement.

switch(ap) {

 

case Jonathan:

 

     ...

 

case Winesap:

 

     ...

 

Notice that in the case statements, the names of the enumeration constants are used without being qualified by their enumeration type name. That is, Winesap, not Apple.Winesap, is used. This is because the type of the enumeration in the switch expression has already implicitly specified the enum type of the case constants. There is no need to qualify the constants in the case statements with their enum type name. In fact, attempting to do so will cause a compilation error.

 

When an enumeration constant is displayed, such as in a println( ) statement, its name is output. For example, given this statement:

 

System.out.println(Apple.Winesap);

the name Winesap is displayed.

 

The following program puts together all of the pieces and demonstrates the Apple enumeration:

 

// An enumeration of apple varieties.

enum Apple {

 

Jonathan, GoldenDel, RedDel, Winesap, Cortland

 

}

 

class EnumDemo {

 

public static void main(String args[])

 

{

 

Apple ap;

 

ap = Apple.RedDel;

 

// Output an enum value.

System.out.println("Value of ap: " + ap); System.out.println();

 

ap = Apple.GoldenDel;

//Compare two enum values.

     if(ap == Apple.GoldenDel)

 

System.out.println("ap contains GoldenDel.\n");

 

     //Use an enum to control a switch statement.

     switch(ap) {

 

case Jonathan:

System.out.println("Jonathan is red."); break;

 

case GoldenDel:

 

System.out.println("Golden Delicious is yellow."); break;

 

case RedDel:

 

System.out.println("Red Delicious is red."); break;

 

case Winesap: System.out.println("Winesap is red."); break;

 

case Cortland: System.out.println("Cortland is red."); break;

 

}

 

}

 

}

 

The output from the program is shown here:

 

Value of ap: RedDel

 

ap contains GoldenDel.

Golden Delicious is yellow.

The values( ) and valueOf( ) Methods

 

All enumerations automatically contain two predefined methods: values( ) and valueOf( ). Their general forms are shown here:

 

public static enum-type [ ] values( ) public static enum-type valueOf(String str )

 

The values( ) method returns an array that contains a list of the enumeration constants. The valueOf( ) method returns the enumeration constant whose value corresponds to the string passed in str. In both cases, enum-type is the type of the enumeration. For example, in the case of the Apple enumeration shown earlier, the return type of Apple.valueOf("Winesap") is Winesap.

 

The following program demonstrates the values( ) and valueOf( ) methods:

 

     Use the built-in enumeration methods.

 

     An enumeration of apple varieties.

 

     enum Apple {

 

Jonathan, GoldenDel, RedDel, Winesap, Cortland

 

}

 

class EnumDemo2 {

 

public static void main(String args[])

 

{

 

Apple ap;

 

System.out.println("Here are all Apple constants:");

 

// use values()

 

Apple allapples[] = Apple.values(); for(Apple a : allapples)

 

System.out.println(a);

 

System.out.println();

 

// use valueOf()

 

ap = Apple.valueOf("Winesap"); System.out.println("ap contains " + ap);

 

}

 

}

 

The output from the program is shown here:

 

Here are all Apple constants:

 

Jonathan

 

GoldenDel

 

RedDel

 

Winesap

 

Cortland

ap contains Winesap

Notice that this program uses a for-each style for loop to cycle through the array of constants obtained by calling values( ). For the sake of illustration, the variable allapples was created and assigned a reference to the enumeration array. However, this step is not necessary because the for could have been written as shown here, eliminating the need for the allapples variable:

for(Apple a : Apple.values())

System.out.println(a);

Now, notice how the value corresponding to the name Winesap was obtained by calling valueOf( ).

 

ap = Apple.valueOf("Winesap");

 

As explained, valueOf( ) returns the enumeration value associated with the name of the constant represented as a string.

 

Java Enumerations Are Class Types

 

As explained, a Java enumeration is a class type. Although you don’t instantiate an enum using new, it otherwise has much the same capabilities as other classes. The fact that enum defines a class gives the Java enumeration extraordinary power. For example, you can give them constructors, add instance variables and methods, and even implement interfaces.

 

It is important to understand that each enumeration constant is an object of its enumeration type. Thus, when you define a constructor for an enum, the constructor is called when each enumeration constant is created. Also, each enumeration constant has its own copy of any instance variables defined by the enumeration. For example, consider the following version of Apple:

 

 

// Use an enum constructor, instance variable, and method.

enum Apple {

 

Jonathan(10), GoldenDel(9), RedDel(12), Winesap(15), Cortland(8); private int price; // price of each apple

 

// Constructor

 

Apple(int p) { price = p; }

 

int getPrice() { return price; }

 

}

 

class EnumDemo3 {

 

public static void main(String args[])

 

{

 

Apple ap;

 

// Display price of Winesap.

System.out.println("Winesap costs " + Apple.Winesap.getPrice() +

cents.\n");

System.out.println("All apple prices:"); for(Apple a : Apple.values())

 

System.out.println(a + " costs " + a.getPrice() + " cents.");

 

}

 

}

 

The output is shown here:

 

Winesap costs 15 cents.

 

All apple prices:

 

Jonathan costs 10 cents.

 

GoldenDel costs 9 cents.

 

RedDel costs 12 cents.

 

Winesap costs 15 cents.

 

Cortland costs 8 cents.

 

This version of Apple adds three things. The first is the instance variable price, which is used to hold the price of each variety of apple. The second is the Apple constructor, which is passed the price of an apple. The third is the method getPrice( ), which returns the value of price.

 

When the variable ap is declared in main( ), the constructor for Apple is called once for each constant that is specified. Notice how the arguments to the constructor are specified, by putting them inside parentheses after each constant, as shown here:

 

Jonathan(10), GoldenDel(9), RedDel(12), Winesap(15), Cortland(8);

 

These values are passed to the p parameter of Apple( ), which then assigns this value to price. Again, the constructor is called once for each constant.

Because each enumeration constant has its own copy of price, you can obtain the price of a specified type of apple by calling getPrice( ). For example, in main( ) the price of a Winesap is obtained by the following call:

 

Apple.Winesap.getPrice( )

 

The prices of all varieties are obtained by cycling through the enumeration using a for loop. Because there is a copy of price for each enumeration constant, the value associated with one constant is separate and distinct from the value associated with another constant. This is a powerful concept, which is only available when enumerations are implemented as classes, as Java does.

 

Although the preceding example contains only one constructor, an enum can offer two or more overloaded forms, just as can any other class. For example, this version of Apple provides a default constructor that initializes the price to –1, to indicate that no price data is available:

 

 

// Use an enum constructor.

enum Apple {

 

Jonathan(10), GoldenDel(9), RedDel, Winesap(15), Cortland(8); private int price; // price of each apple

// Constructor

 

Apple(int p) { price = p; }

 

// Overloaded constructor

Apple() { price = -1; }

 

int getPrice() { return price; }

 

}

 

Notice that in this version, RedDel is not given an argument. This means that the default constructor is called, and RedDel’s price variable is given the value –1.

Here are two restrictions that apply to enumerations. First, an enumeration can’t inherit another class. Second, an enum cannot be a superclass. This means that an enum can’t be extended. Otherwise, enum acts much like any other class type. The key is to remember that each of the enumeration constants is an object of the class in which it is defined.

 

Enumerations Inherit Enum

 

Although you can’t inherit a superclass when declaring an enum, all enumerations automatically inherit one: java.lang.Enum. This class defines several methods that are available for use by all enumerations. The Enum class is described in detail in Part II, but three of its methods warrant a discussion at this time.

 

You can obtain a value that indicates an enumeration constant’s position in the list of constants. This is called its ordinal value, and it is retrieved by calling the ordinal( ) method, shown here:

 

final int ordinal( )

 

It returns the ordinal value of the invoking constant. Ordinal values begin at zero. Thus, in the Apple enumeration, Jonathan has an ordinal value of zero, GoldenDel has an ordinal value of 1, RedDel has an ordinal value of 2, and so on.

You can compare the ordinal value of two constants of the same enumeration by using the compareTo( ) method. It has this general form:

 

final int compareTo(enum-type e)

 

Here, enum-type is the type of the enumeration, and e is the constant being compared to the invoking constant. Remember, both the invoking constant and e must be of the same enumeration. If the invoking constant has an ordinal value less than e’s, then compareTo( ) returns a negative value. If the two ordinal values are the same, then zero is returned. If the invoking constant has an ordinal value greater than e’s, then a positive value is returned.

You can compare for equality an enumeration constant with any other object by using equals( ), which overrides the equals( ) method defined by Object. Although equals( ) can compare an enumeration constant to any other object, those two objects will be equal only if they both refer to the same constant, within the same enumeration. Simply having ordinal values in common will not cause equals( ) to return true if the two constants are from different enumerations.

Remember, you can compare two enumeration references for equality by using = =.

The following program demonstrates the ordinal( ), compareTo( ), and equals( ) methods:

 

     Demonstrate ordinal(), compareTo(), and equals().

 

     An enumeration of apple varieties.

 

enum Apple {

 

Jonathan, GoldenDel, RedDel, Winesap, Cortland

 

}

 

class EnumDemo4 {

 

public static void main(String args[])

 

{

 

Apple ap, ap2, ap3;

 

// Obtain all ordinal values using ordinal().

System.out.println("Here are all apple constants" +

 

" and their ordinal values: ");

for(Apple a : Apple.values())

 

System.out.println(a + " " + a.ordinal());

 

ap = Apple.RedDel; ap2 = Apple.GoldenDel; ap3 = Apple.RedDel;

 

System.out.println();

 

// Demonstrate compareTo() and equals()

if(ap.compareTo(ap2) < 0)

 

System.out.println(ap + " comes before " + ap2);

 

if(ap.compareTo(ap2) > 0)

 

System.out.println(ap2 + " comes before " + ap);

 

if(ap.compareTo(ap3) == 0) System.out.println(ap + " equals " + ap3);

 

System.out.println();

 

if(ap.equals(ap2))

 

System.out.println("Error!");

 

if(ap.equals(ap3))

 

System.out.println(ap + " equals " + ap3);

 

if(ap == ap3)

 

System.out.println(ap + " == " + ap3);

 

}

 

}

 

The output from the program is shown here:

Here are all apple constants and their ordinal values: Jonathan 0

 

 

GoldenDel 1

 

RedDel 2

 

Winesap 3

 

Cortland 4

 

GoldenDel comes before RedDel

 

RedDel equals RedDel

 

RedDel equals RedDel

 

RedDel == RedDel

 

Another Enumeration Example

 

Before moving on, we will look at a different example that uses an enum. In Chapter 9, an automated “decision maker” program was created. In that version, variables called NO, YES, MAYBE, LATER, SOON, and NEVER were declared within an interface and used to represent the possible answers. While there is nothing technically wrong with that approach, the enumeration is a better choice. Here is an improved version of that program that uses an enum called Answers to define the answers. You should compare this version to the original in Chapter 9.

 

 

    An improved version of the "Decision Maker"

 

    program from Chapter 9. This version uses an

 

    enum, rather than interface variables, to

 

    represent the answers.

 

import java.util.Random;

 

 

// An     enumeration of the possible answers.

enum Answers  {        

NO,  YES, MAYBE, LATER, SOON, NEVER

}                 

class     Question {        

Random rand = new Random(); 

Answers ask() {        

int  prob =    (int) (100 * rand.nextDouble());

if (prob  < 15)        

     return    Answers.MAYBE; //  15%

else if (prob < 30)    

     return    Answers.NO;   //   15%

else if (prob < 60)    

     return    Answers.YES;  //   30%

else if (prob < 75)    

     return    Answers.LATER; //  15%

else if (prob < 98)    

     return    Answers.SOON; //   13%

else         

     return    Answers.NEVER; //  2%

}                 

}                 

class AskMe {

 

static void answer(Answers result) { switch(result) {

 

case NO: System.out.println("No"); break;

 

case YES: System.out.println("Yes"); break;

 

case MAYBE: System.out.println("Maybe"); break;

 

case LATER: System.out.println("Later"); break;

 

case SOON: System.out.println("Soon"); break;

 

case NEVER: System.out.println("Never"); break;

 

}

 

}

 

public static void main(String args[]) { Question q = new Question(); answer(q.ask());

 

answer(q.ask());

 

answer(q.ask());

 

answer(q.ask());

 

}

 

}


Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail


Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.