你好!今天我們就來聊一聊Java的一種特殊數據類型:
看起來沒有問題,對吧?我們只需要確定任何月份都有哪些屬性。也許我們首先需要月份的名稱和其中的天數。解決方案看起來很簡單:
作者是 Java 的創造者之一,因此您絕對可以相信他關於如何正確和熟練地使用語言工具的建議 :) 關於我們的課程,我建議您特別注意本書關於
Enum
(enumeration的簡稱)。是什麼讓它與眾不同?讓我們想像一下我們需要在程序中實現“幾個月”。 
public class Month {
private String name;
private int daysCount;
public Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDaysCount() {
return daysCount;
}
public void setDaysCount(int daysCount) {
this.daysCount = daysCount;
}
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
整個沙邦!我們有一個Month
類、必填字段、getter/setter 和toString()
. 當然,除非我們需要添加equals()
和hashCode()
獲得完全的幸福 :) 但是這裡我們有一個概念上的問題。您可能還記得,OOP 的主要優點之一是它可以輕鬆地為現實世界中的實體建模。一把椅子、一輛汽車、一顆行星——所有這些來自日常生活的概念都可以在抽象的幫助下很容易地在程序中表示。問題在於一些現實世界的實體具有嚴格限制的值範圍。一年只有 4 個季節。一個八度只有8個音符。日曆只有 12 個月。Ocean's 11 的 Danny Ocean 只有 11 個朋友(儘管這無關緊要 :))重要的是普通的 Java 類無法對這些實體建模並強制執行它們的自然限制。我們的Month
類具有所有必填字段。但是如果另一個程序員使用它,沒有人能阻止他或她創建完全瘋狂的對象:
public class Main {
Month month1 = new Month("lolkek", 322);
Month month2 = new Month("yahoooooooooooo", 12345);
}
如果這齣現在我們的代碼中,就不容易找到罪魁禍首了!一方面,創建對象的程序員可能會意識到類的Month
意思是“一年中的一個月”,而不是寫這種廢話。另一方面,程序員只是在利用類設計者提供的能力。是否可以指定任意名稱和天數?這正是我們得到的。那麼在這種情況下我們應該怎麼辦呢?老實說,在 Java 1.5 發布之前,程序員必鬚髮揮創造力 :) 在那些日子裡,他們創建了這樣的結構:
public class Month {
private String name;
private int daysCount;
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public static Month JANUARY = new Month("January", 31);
public static Month FEBRUARY = new Month("February", 28);
public static Month MARCH = new Month("March", 31);
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
在這裡,我們將月數從 12 減少到 3,以使示例更短。這樣的設計使得解決問題成為可能。創建對象的能力僅限於私有構造函數:
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
使用該類的程序員不能簡單地創建Month
對象。他們不得不使用類開發人員提供的最終靜態對象。例如,像這樣:
public class Main {
public static void main(String[] args) {
Month january = Month.JANUARY;
System.out.println(january);
}
}
但是,Java 開發人員提請注意現有問題。當然,程序員能夠使用該語言中可用的工具想出一個解決方案真是太好了,但這看起來並不容易!需要一個明顯的解決方案,即使對於新手也是如此。因此Enum
出現在Java中。基本上,Enum
它是一個提供一組有限對象值的 Java 類。這是它的樣子:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
在定義中,我們指出這Enum
是一個 Java 類,但事實真的如此嗎?是的,我們甚至可以驗證它。例如,嘗試讓我們的Month
枚舉繼承一些其他類:
public abstract class AbstractMonth {
}
// Error! The extends clause cannot be used with an enum
public enum Month extends AbstractMonth {
JANUARY,
FEBRUARY,
MARCH
}
為什麼會這樣?當我們寫:
public enum Month
編譯器將此語句轉換為以下代碼:
public Class Month extends Enum
如您所知,Java 不支持多重繼承。因此,我們不能繼承AbstractMonth
。如何Enum
使用這個新結構?它與帶有字段的舊構造有何不同static final
?好吧,舉個例子,舊的結構不允許我們在switch
語句中使用我們自己的一組值。想像一下,我們想要創建一個程序來提醒我們每個月慶祝的假期:
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
// Error!
case JANUARY:
}
}
}
如您所見,編譯器在此處拋出錯誤。但是一旦enum
出現在 Java 1.5 中,一切就變得簡單多了:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
case JANUARY:
System.out.println("New Year's Day is January 1st!");
break;
case FEBRUARY:
System.out.println("Valentine's Day is February 14th!");
break;
case MARCH:
System.out.println("Saint Patrick's Day is March 17th!");
break;
}
}
}
public class Main {
public static void main(String[] args) {
HolidayReminder reminder = new HolidayReminder();
reminder.printHolidays(Month.JANUARY);
}
}
控制台輸出:
New Year's Day is January 1st!
請注意,對對象的訪問Enum
仍然是靜態的,就像 Java 1.5 之前一樣。我們不需要創建Month
對象來訪問月份。使用枚舉時,不要忘記它Enum
是一個完整的類,這一點非常重要。這意味著,如果需要,您可以在其中定義構造函數和方法。例如,在前面的代碼片段中,我們簡單地指定了值:JANUARY、FEBRUARY、MARCH。Month
但是,我們可以像這樣 擴展我們的枚舉:
public enum Month {
JANUARY("January", 31),
FEBRUARY("February", 28),
MARCH("March", 31),
APRIL("April", 30),
MAY("May", 31),
JUNE("June", 30),
JULY("July", 31),
AUGUST("August", 31),
SEPTEMBER("September", 30),
OCTOBER("October", 31),
NOVEMBER("November", 30),
DECEMBER("December", 31);
private String name;
private int daysCount;
Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public static Month[] getWinterMonths() {
return new Month[]{DECEMBER, JANUARY, FEBRUARY};
}
public static Month[] getSummerMonths() {
return new Month[]{JUNE, JULY, AUGUST};
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDaysCount() {
return daysCount;
}
public void setDaysCount(int daysCount) {
this.daysCount = daysCount;
}
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
這裡我們給出了enum
2 個字段(月份名稱和天數)、使用這些字段的構造函數、getter/setter、方法toString()
和 2 個靜態方法。如您所見,這沒有問題。再一次,Enum
真的是一個完整的類:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
System.out.println(Arrays.toString(Month.getSummerMonths()));
}
}
控制台輸出:
[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
最後,我想推荐一本非常有用的Java書籍,即Joshua Bloch的《Effective Java》。 
Enum
. 閱讀愉快!:)
GO TO FULL VERSION