前面介紹了聯合利用final和static可實現常量的定義,該方式用於簡單的常量倒還湊合,要是用於複雜的、安全性高的常量,那就力不從心了。例如如下幾種狀況,final結合static的方式便缺少應對之策:
一、雖然常量的名稱以大寫字母拼寫,可是對應的取值基本爲一、二、3之類的整數,若是把一、二、3直接寫在調用的代碼裏面,豈不是渾水摸魚頂替了現有的常量矇混過關?
二、代碼能夠從常量名推出對應的常量值,但是反過來並不能從常量值推出對應的常量名,開發者曉得不表明程序也曉得。
三、每一個常量只有惟一的數值表達,沒法表示更豐富的涵義。好比星期一這個常量,可能包括數字「1」、英文單詞「Monday」、中文詞語「星期一」這些信息組合,然而final聯合static的方式只能表達其中一個信息。
聽起來彷佛言之有理,但是不用整型常量的話,還有什麼常量類型能派上用場呢?其實Java語言在設計之初就考慮到了這種狀況,在以前的學習當中,已經出現過相似的處理方案。早在介紹本地日期類型LocalDate的時候,提到獲取當前月份的辦法是調用日期實例的getMonthValue方法,爲啥這裏不是調用getMonth方法?原來getMonth方法返回的並不是整型數值,而是一個Month類型的月份實例,它屬於枚舉類型。調用該實例的getValue方法,獲得的纔是月份數字;調用該實例的name方法,可獲得大寫英文月份的英文單詞。先來看看如下的一段月份測試代碼:html
// 演示Month類型的調用方式。注意,Month類型是Java自帶的一種枚舉類型 private static void testMonth() { LocalDate date = LocalDate.now(); Month month = date.getMonth(); System.out.println("month number="+month.getValue()+", month name="+month.name()); }
運行以上的測試代碼,觀察到以下的日誌文本:java
month number=12, month name=DECEMBER
根據結果發現getValue方法返回了12,且name方法返回了DECEMBER。從中可見Month類型既包含了月份的數字信息,也包括了月份的英文單詞,這正是枚舉類型相對於普一般量的優點。
所謂枚舉,指的是某些同類型常量的有限集合。Java不但提供了Month這種枚舉類型,並且容許程序員本身定義新的枚舉類型,如同定義類那樣。不一樣的是,類定義使用class來標識,而枚舉類型使用enum來標識。最簡單的枚舉定義只需一個名稱列表,就像如下代碼這般:程序員
//演示枚舉類型的簡單定義 public enum Season { // 幾個枚舉變量之間以逗號分隔 SPRING, SUMMER, AUTUMN, WINTER }
以上代碼定義了一種季節枚舉Season,它包含了春天SPRING、夏天SUMMER、秋天AUTUMN、冬天WINTER這四個枚舉項。四個枚舉項既是常量,又都屬於Season類型,外部訪問它們的格式爲「Season.枚舉項的名稱」。下面是外部訪問季節枚舉項的代碼例子:spring
// 演示簡單枚舉類型的調用方式 private static void testEnum() { Season spring = Season.SPRING; // 聲明一個春天的季節實例 Season summer = Season.SUMMER; // 聲明一個夏天的季節實例 Season autumn = Season.AUTUMN; // 聲明一個秋天的季節實例 Season winter = Season.WINTER; // 聲明一個冬天的季節實例 // 枚舉類型提供的通用方法主要有兩個, // 其中ordinal方法可得到該枚舉的序號,toString可得到該枚舉的字段名稱 System.out.println("spring number="+spring.ordinal()+", name="+spring.toString()); System.out.println("summer number="+summer.ordinal()+", name="+summer.toString()); System.out.println("autumn number="+autumn.ordinal()+", name="+autumn.toString()); System.out.println("winter number="+winter.ordinal()+", name="+winter.toString()); }
運行上面的測試代碼,輸出下列的日誌信息:安全
spring number=0, name=SPRING summer number=1, name=SUMMER autumn number=2, name=AUTUMN winter number=3, name=WINTER
結合代碼和日誌結果,可知枚舉項的ordinal方法返回了該枚舉所處的序號,toString方法返回了該枚舉的常量名稱。因爲ordinal方法和toString方法是枚舉類型enum自帶的保留方法,所以無需開發者顯式定義便可拿來調用。然而這兩個方法畢竟是系統提供的,沒法知足豐富多變的個性要求,譬以下列兩點需求,簡單的枚舉類型就沒法實現:
一、枚舉項的默認序號從0開始計數,但現實生活中不少組合是從1開始計數的。例如一月份對應的數字是1,星期一對應的數字也是1,諸如此類。
二、枚舉項的默認名稱取的是枚舉定義裏的列表項名稱,但每每更須要中文名稱。例如界面上但願展現「春天」而非「SPRING」,但願展現「夏天」而非「SUMMER」,等等。
既然枚舉的默認序號與默認名稱時常不符合實際狀況,這勢必要求開發者額外定義新的序號和新的名稱。假如說給某個類定義新的屬性,那真是易如反掌,可如今待處理的是枚舉類型而不是類耶。其實枚舉類型enum原本就源自類class,故而徹底能夠把枚舉看成類同樣來定義,也就是說,枚舉容許定義本身的成員屬性、本身的成員方法,乃至本身的構造方法。因而從新定義一個季節枚舉,在新的枚舉定義中添加序號與名稱這兩個屬性,及其對應的get方法,並補充包含初始化賦值的構造方法。特別注意要在枚舉項列表中把每一個枚舉項都換成攜帶構造方法的枚舉聲明,表示該枚舉項是由指定構造方法生成的,重寫後的季節枚舉定義代碼示例以下:學習
//演示枚舉類型的擴展定義 public enum SeasonCn { // 在定義枚舉變量的同時,調用該枚舉變量的構造方法 SPRING(1,"春天"), SUMMER(2,"夏天"), AUTUMN(3,"秋天"), WINTER(4,"冬天"); private int value; // 定義季節的阿拉伯數字 private String name; // 定義季節的中文名稱字段 // 在構造方法中傳入該季節的阿拉伯數字和中文名稱 private SeasonCn(int value, String name) { this.value = value; this.name = name; } // 獲取季節的阿拉伯數字 public int getValue() { return this.value; } // 獲取季節的中文名稱 public String getName() { return this.name; } }
根據新的枚舉定義代碼,枚舉項的序號數值與中文名稱如願換了過來。接着輪到外部調用新的枚舉類型,大體流程保持不變,只需將原來的ordinal方法替換爲getValue方法,將原來的toString方法替換爲getName方法。修改以後的調用代碼以下所示:測試
// 演示擴展枚舉類型的調用方式 private static void testEnumCn() { SeasonCn spring = SeasonCn.SPRING; // 聲明一個春天的季節實例 SeasonCn summer = SeasonCn.SUMMER; // 聲明一個夏天的季節實例 SeasonCn autumn = SeasonCn.AUTUMN; // 聲明一個秋天的季節實例 SeasonCn winter = SeasonCn.WINTER; // 聲明一個冬天的季節實例 // 經過擴展而來的getName方法,可得到該枚舉預先設定的中文名稱 System.out.println("spring number="+spring.getValue()+", name="+spring.getName()); System.out.println("summer number="+summer.getValue()+", name="+summer.getName()); System.out.println("autumn number="+autumn.getValue()+", name="+autumn.getName()); System.out.println("winter number="+winter.getValue()+", name="+winter.getName()); }
運行上述的調用代碼,獲得如下的日誌結果:this
spring number=1, name=春天 summer number=2, name=夏天 autumn number=3, name=秋天 winter number=4, name=冬天
因而可知,通過從新編寫的SeasonCn枚舉,順利實現了個性化定製序號和名稱的目標。設計
更多Java技術文章參見《Java開發筆記(序)章節目錄》日誌