|
Grouping constants
Because any fields you put into an interface are automatically static and final, the interface is a convenient tool for creating groups of constant values, much as you would with an enum in C or C++. For example:
//: c08:Months.java
// Using interfaces to create groups of constants.
package c08;
public interface Months {
int
JANUARY = 1, FEBRUARY = 2, MARCH = 3,
APRIL = 4, MAY = 5, JUNE = 6, JULY = 7,
AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,
NOVEMBER = 11, DECEMBER = 12;
} ///:~
Notice the Java style of using all uppercase letters (with underscores to separate multiple words in a single identifier) for static finals that have constant initializers.
The fields in an interface are automatically public, so it’s unnecessary to specify that.
You can use the constants from outside the package by importing c08.* or c08.Months just as you would with any other package, and referencing the values with expressions like Months.JANUARY. Of course, what you get is just an int, so there isn’t the extra type safety that C++’s enum has, but this (commonly used) technique is certainly an improvement over hard coding numbers into your programs. (That approach is often referred to as using “magic numbers,” and it produces very difficult-to-maintain code.)
If you do want extra type safety, you can build a class like this:[33]
//: c08:Month.java
// A more robust enumeration system.
package c08;
import com.bruceeckel.simpletest.*;
public final class Month {
private static Test monitor = new Test();
private String name;
private Month(String nm) { name = nm; }
public String toString() { return name; }
public static final Month
JAN = new Month("January"),
FEB = new Month("February"),
MAR = new Month("March"),
APR = new Month("April"),
MAY = new Month("May"),
JUN = new Month("June"),
JUL = new Month("July"),
AUG = new Month("August"),
SEP = new Month("September"),
OCT = new Month("October"),
NOV = new Month("November"),
DEC = new Month("December");
public static final Month[] month = {
JAN, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC
};
public static final Month number(int ord) {
return month[ord - 1];
}
public static void main(String[] args) {
Month m = Month.JAN;
System.out.println(m);
m = Month.number(12);
System.out.println(m);
System.out.println(m == Month.DEC);
System.out.println(m.equals(Month.DEC));
System.out.println(Month.month[3]);
monitor.expect(new String[] {
"January",
"December",
"true",
"true",
"April"
});
}
} ///:~
Month is a final class with a private constructor, so no one can inherit from it or make any instances of it. The only instances are the final static ones created in the class itself: JAN, FEB, MAR, etc. These objects are also used in the array month, which lets you iterate through an array of Month2 objects. The number( ) method allows you to select a Month by giving its corresponding month number. In main( ) you can see the type safety; m is a Month object so it can be assigned only to a Month. The previous example Months.java provided only int values, so an int variable intended to represent a month could actually be given any integer value, which wasn’t very safe.
This approach also allows you to use == or equals( ) interchangeably, as shown at the end of main( ). This works because there can be only one instance of each value of Month. In Chapter 11 you’ll learn about another way to set up classes so the objects can be compared to each other.
There’s also a month field in java.util.Calendar.
Apache’s Jakarta Commons project contains tools to create enumerations similar to what’s shown in the preceding example, but with less effort. See https://jakarta.apache.org/commons, under “lang,” in the package org.apache.commons.lang.enum. This project also has many other potentially useful libraries.
|
|