Now that we’ve covered the basics of classes, we can talk a bit more in depth about enumerations. As we’ve discussed, an enumeration is an object type in the Java language that is limited to an explicit set of values. The values have an order that is 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 compiled 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 Chapter 4, 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 Java static import, saving us some typing:
import
static
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 Chapter 6).
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 Weekday
s, 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
.
LOW
;
Level
anotherLevel
=
Level
.
HIGH
;
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.
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 Chapter 6.) You
could use this to have the Persian
member override a method in the base enum class.
Get Learning Java, 4th Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.