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());
}
}
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.