由於置入一個接口的所有字段都自動具有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()尾部展示的那樣。