JavaRush /Java Blog /Random-TW /Java 中的列舉。實際例子。新增建構函式和方法

Java 中的列舉。實際例子。新增建構函式和方法

在 Random-TW 群組發布
你好!今天我們要講的是Java中一種特殊的資料型別-Enum(枚舉的簡稱)。他們的特點是什麼?讓我們想像一下我們需要在該計劃中實施幾個月。 枚舉。 實際例子。 新增建構函式和方法 - 1如此看來,問題出在哪裡呢?您只需要確定任何月份都有哪些屬性。也許我們首先需要月份的名稱和月份的天數。問題的解決方案看起來很簡單:
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,必要的字段,getters-setters toString(),。除非equals()hashCode()需要添加它以獲得完全的幸福:)但是,我們有一個概念問題。您可能還記得,OOP 的主要優點之一是它可以輕鬆地對現實世界的實體進行建模。一把椅子、一輛汽車、一個星球——所有這些日常生活中的概念都可以很容易地在程式中使用抽象來表示。問題在於現實世界中的某些實體的含義範圍受到嚴格限制。一年只有4個季節。音樂只有7個音符。日曆上只有12個月。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("Январь", 31);
   public static Month FEBRUARY = new Month("Февраль", 28);
   public static Month MARCH = new Month("Март", 31);

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
在這裡,我們將月份數簡化為三個月,而不是十二個月,以使範例更簡短。這樣的設計使得解決這個問題成為可能。建立物件的選項受到私有建構函數的限制:
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 開發人員注意到了一個現有的問題。當然,很高興程式設計師能夠使用該語言中提供的工具提出解決方案,但它看起來並不那麼簡單!我們需要一個顯而易見的解決方案,即使是初學者也可以使用。這就是 . 在 Java 中的出現方式Enum。本質上,Enum它是一個提供一組有限值物件的 Java 類別。它看起來是這樣的:
public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}
在定義中,我們指出Enum這是一個 Java 類,但這真的是這樣嗎?是的,我們甚至可以檢查它。例如,嘗試enum Month從其他類別繼承我們的類別:
public abstract class AbstractMonth {
}

//ошибка! No extends clause allowed to 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:
       }
   }
}
正如您所看到的,編譯器在這裡拋出了一個錯誤。但Java 1.5出現之後enum,一切都變得簡單多了:
public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           case JANUARY:
               System.out.println("7 января будет Рождество!");
               break;
           case FEBRUARY:
               System.out.println("В феврале празднуется День Защитника Отечества - 23 февраля!");
               break;
           case MARCH:
               System.out.println("В марте отмечается Всемирный Женский День - 8 марта!");
               break;
       }
   }
}



public class Main {

   public static void main(String[] args) {

       HolidayReminder reminder = new HolidayReminder();
       reminder.printHolidays(Month.JANUARY);

   }

}
控制台輸出:

7 января будет Рождество!
請注意:對物件的存取Enum保持靜態,就像 Java 1.5 之前一樣。我們不需要建立一個物件Month來存取月份。當使用枚舉時,不要忘記Enum這是一個成熟的類,這一點非常重要。這意味著,如果需要,您可以在其中定義建構函式和方法。例如,在前面的程式碼中我們簡單地指定了值JANUARY、FEBRUARY、MARCH。但是,我們可以enum Month這樣擴展:
public enum Month {

   JANUARY("Январь", 31),
   FEBRUARY("Февраль", 28),
   MARCH("Март", 31),
   APRIL("Апрель", 30),
   MAY("Май", 31),
   JUNE("Июнь", 30),
   JULY("Июль", 31),
   AUGUST("Август", 31),
   SEPTEMBER("Сентябрь", 30),
   OCTOBER("Октябрь", 31),
   NOVEMBER("Ноябрь", 30),
   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 +
               '}';
   }
}
在這裡,我們新增了 2 個欄位enum- 月份名稱和天數、使用這些欄位的建構函式、getters-setters、方法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='Июнь', daysCount=30}, Month{name='Июль', daysCount=31}, Month{name='Август', daysCount=31}]
最後,我想向您推薦一本關於Java非常有用的書,即Joshua Bloch的《Effective Java》枚舉。 實際例子。 新增建構函式和方法 - 3作者是 Java 的創建者之一,因此您絕對可以相信他關於正確且有效地使用語言工具的建議:) 關於我們的講座,我建議您特別注意本書中專門討論enum. 祝您閱讀愉快!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION