こんにちは!
Enum
今日は、Java の特別なデータ型(列挙の略)について説明します。彼らの特徴は何でしょうか?プログラムに何か月も実装する必要があると想像してみましょう。 何が問題なのでしょうか?必要なのは、月にどのようなプロパティがあるかを判断することだけです。おそらく、まず第一に、月の名前とその日数が必要になるでしょう。この問題の解決策は非常に簡単に見えます。
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
、必要なフィールド、ゲッターセッター、 がありますtoString()
。equals()
完全に幸せになるためにそれを追加する必要がある場合を除きますhashCode()
:) ただし、概念的な問題があります。覚えているかもしれませんが、OOP の主な利点の 1 つは、現実世界のエンティティのモデル化が容易になることです。椅子、車、惑星など、日常生活のこれらすべての概念は、抽象化を使用してプログラムで簡単に表現できます。問題は、現実世界の一部のエンティティの意味範囲が厳密に制限されていることです。一年には季節が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 がリリースされる前は、率直に言って、プログラマは 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 +
'}';
}
}
ここでは例を短くするために、月数を 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 開発者は、既存の問題に気づきました。もちろん、プログラマーがその言語で利用可能なツールを使用して解決策を考え出すことができたのは素晴らしいことですが、それはそれほど単純ではないようです。初心者でもアクセスできる明確な解決策が必要でした。これが 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 +
'}';
}
}
enum
ここでは、月の名前と日数の 2 つのフィールド、これらのフィールドを使用するコンストラクター、ゲッターセッター、メソッド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 に関する非常に役立つ本を 1 冊お勧めします。それは、Joshua Bloch 著の『Effective Java』です。 著者は Java の作成者の 1 人であるため、言語ツールの正しく有能な使用法に関する彼のアドバイスは間違いなく信頼できます :) 私たちの講義に関連して、この本の に特化した章に特に注意を払うことをお勧めしますenum
。生産的な読書をお楽しみください。:)
GO TO FULL VERSION