由於置入一個接口的所有字段都自動具有static和final屬性,所以接口是對常數值進行分組的一個好工具,它具有與C或C++的enum非常相似的效果。如下例所示:
//: Months.java
// Using interfaces to create groups of constants
package c07;
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;
} ///:~
注意根據Java命名規則,擁有固定標識符的static final基本數據類型(亦即編譯期常數)都全部采用大寫字母(用下劃線分隔單個標識符裡的多個單詞)。
接口中的字段會自動具備public屬性,所以沒必要專門指定。
現在,通過導入c07.*或c07.Months,我們可以從包的外部使用常數——就象對其他任何包進行的操作那樣。此外,也可以用類似Months.JANUARY的表達式對值進行引用。當然,我們獲得的只是一個int,所以不象C++的enum那樣擁有額外的類型安全性。但與將數字強行編碼(硬編碼)到自己的程序中相比,這種(常用的)技術無疑已經是一個巨大的進步。我們通常把“硬編碼”數字的行為稱為“魔術數字”,它產生的代碼是非常難以維護的。
如確實不想放棄額外的類型安全性,可構建象下面這樣的一個類(注釋①):
//: Month2.java
// A more robust enumeration system
package c07;
public final class Month2 {
private String name;
private Month2(String nm) { name = nm; }
public String toString() { return name; }
public final static Month2
JAN = new Month2("January"),
FEB = new Month2("February"),
MAR = new Month2("March"),
APR = new Month2("April"),
MAY = new Month2("May"),
JUN = new Month2("June"),
JUL = new Month2("July"),
AUG = new Month2("August"),
SEP = new Month2("September"),
OCT = new Month2("October"),
NOV = new Month2("November"),
DEC = new Month2("December");
public final static Month2[] month = {
JAN, JAN, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC
};
public static void main(String[] args) {
Month2 m = Month2.JAN;
System.out.println(m);
m = Month2.month[12];
System.out.println(m);
System.out.println(m == Month2.DEC);
System.out.println(m.equals(Month2.DEC));
}
} ///:~
①:是Rich Hoffarth的一封E-mail觸發了我這樣編寫程序的靈感。
這個類叫作Month2,因為標准Java庫裡已經有一個Month。它是一個final類,並含有一個private構建器,所以沒有人能從它繼承,或制作它的一個實例。唯一的實例就是那些final static對象,它們是在類本身內部創建的,包括:JAN,FEB,MAR等等。這些對象也在month數組中使用,後者讓我們能夠按數字挑選月份,而不是按名字(注意數組中提供了一個多余的JAN,使偏移量增加了1,也使December確實成為12月)。在main()中,我們可注意到類型的安全性:m是一個Month2對象,所以只能將其分配給Month2。在前面的Months.java例子中,只提供了int值,所以本來想用來代表一個月份的int變量可能實際獲得一個整數值,那樣做可能不十分安全。
這兒介紹的方法也允許我們交換使用==或者equals(),就象main()尾部展示的那樣。