7ステップで理解するJavaでの列挙型/enum使用法:【改訂版】Eclipseではじめるプログラミング(21)(3/3 ページ)
これからプログラミングを学習したい方、Javaは難しそうでとっつきづらいという方のためのJavaプログラミング超入門連載です。最新のEclipseとJava 6を使い大幅に情報量を増やした、連載「Eclipseではじめるプログラミング」の改訂版となります
【Step 5】列挙型を使って日本語でも各月の名前を表示
もう1つ列挙型の例を見てみましょう。int enumパターンでは複数の値をまとめて管理できませんが、メソッドやフィールドを持つ列挙型を使うことにより実現できます。ここでは、列挙定数の文字列だけでなく、日本語でも各月の名前を表示できるようにしてみます。
package sample21;
public class EnumJapaneseMonthList {
enum Month {
JANUARY("睦月"),
FEBRUARY("如月"),
MARCH("弥生"),
APRIL("卯月"),
MAY("皐月"),
JUNE("水無月"),
JULY("文月"),
AUGUST("葉月"),
SEPTEMBER("長月"),
OCTOBER("神無月"),
NOVEMBER("霜月"),
DECEMBER("師走");
private String name;
Month(String name) { this.name = name; }
public String getName() { return name; }
}
public void exec() {
for (Month m : Month.values()) {
System.out.println(m + ":" + m.getName());
}
}
public static void main(String[] args) {
EnumJapaneseMonthList app = new EnumJapaneseMonthList();
app.exec();
}
}
JANUARY:睦月 FEBRUARY:如月 MARCH:弥生 APRIL:卯月 MAY:皐月 JUNE:水無月 JULY:文月 AUGUST:葉月 SEPTEMBER:長月 OCTOBER:神無月 NOVEMBER:霜月 DECEMBER:師走
EnumJapaneseMonthListクラス内のMonth型では、文字列を引数とするコンストラクタを用意して、そこで与えられた文字列をnameフィールドへ保持しています。
【Step 6】管理しやすい「java.utilEnumMap」を使う
列挙定数と対応するメッセージを一緒に管理したり、列挙定数と対応する整数値やオブジェクトを一緒に管理したりしたい場合があります。そんなときは、「java.util.EnumMap」クラスを使います。
次の例では、各月の名前と、整数値を対応させて、EnumMapを使って一緒に管理しています。int enumパターンで実装した「2011年の各月に何日あるか表示するプログラム」と同じ動作をするプログラムです。
package sample21;
import java.util.EnumMap;
public class EnumMapMonthList {
private enum Month {
JANUARY, FEBRUARY, MARCH, APRIL,
MAY, JUNE, JULY, AUGUST,
SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER;
}
private EnumMap<Month, Integer> monthMap;
public EnumMapMonthList() {
monthMap = new EnumMap<Month, Integer>(Month.class);
monthMap.put(Month.JANUARY, 1);
monthMap.put(Month.FEBRUARY, 2);
monthMap.put(Month.MARCH, 3);
monthMap.put(Month.APRIL, 4);
monthMap.put(Month.MAY, 5);
monthMap.put(Month.JUNE, 6);
monthMap.put(Month.JULY, 7);
monthMap.put(Month.AUGUST, 8);
monthMap.put(Month.SEPTEMBER, 9);
monthMap.put(Month.OCTOBER, 10);
monthMap.put(Month.NOVEMBER, 11);
monthMap.put(Month.DECEMBER, 12);
}
public void exec() {
System.out.println("2011年");
for (Month m : Month.values()) {
String s = monthMap.get(m) + "月";
switch (m) {
case FEBRUARY:
s = s + ":" + m + "(28日)";
break;
case APRIL:
case JUNE:
case SEPTEMBER:
case NOVEMBER:
s = s + ":" + m + "(30日)";
break;
case JANUARY:
case MARCH:
case MAY:
case JULY:
case AUGUST:
case OCTOBER:
case DECEMBER:
s = s + ":" + m + "(31日)";
break;
}
System.out.println(s);
}
}
public static void main(String[] args) {
EnumMapMonthList app = new EnumMapMonthList();
app.exec();
}
}
switch文の判別式に、列挙型の変数を指定している点、case文では列挙定数を指定する点に注目してください。
2011年 1月:JANUARY(31日) 2月:FEBRUARY(28日) 3月:MARCH(31日) 4月:APRIL(30日) 5月:MAY(31日) 6月:JUNE(30日) 7月:JULY(31日) 8月:AUGUST(31日) 9月:SEPTEMBER(30日) 10月:OCTOBER(31日) 11月:NOVEMBER(30日) 12月:DECEMBER(31日)
ここでは、数値を対応させていますが、例えば、JANUARYに「JAN.」という略称を対応させたい場合は、「EnumMap
【Step 7】「java.util.EnumSet」クラスでビット和操作
列挙定数にビット演算しやすい値を指定したいときがあります。
int enumパターンでビット和操作
例えば、上下左右の矢印キーを組み合わせて使えるようにしたいとします。これは、int enumパターンでの実装なら、各キーの値を下記のように対応させることにより、ビット和操作などができるようになります。
package sample21;
import java.util.ArrayList;
import java.util.List;
public class ArrowKeysSample {
class ArrowKeys {
public static final int UP = 0x01;
public static final int RIGHT = 0x02;
public static final int DOWN = 0x04;
public static final int LEFT = 0x08;
}
public void exec() {
List<Integer> keys = new ArrayList<Integer>();
keys.add(ArrowKeys.UP);
keys.add(ArrowKeys.RIGHT);
keys.add(ArrowKeys.UP+ArrowKeys.RIGHT);
keys.add(ArrowKeys.DOWN);
keys.add(ArrowKeys.UP+ArrowKeys.DOWN);
keys.add(ArrowKeys.UP+ArrowKeys.RIGHT + ArrowKeys.DOWN+ArrowKeys.LEFT);
for (int e : keys) {
System.out.print(e + ":");
if ((e & ArrowKeys.UP) != 0) {
System.out.print("UP, ");
}
if ((e & ArrowKeys.RIGHT) != 0) {
System.out.print("RIGHT, ");
}
if ((e & ArrowKeys.DOWN) != 0) {
System.out.print("DOWN, ");
}
if ((e & ArrowKeys.LEFT) != 0) {
System.out.print("LEFT, ");
}
System.out.println("");
}
}
public static void main(String[] args) {
ArrowKeysSample app = new ArrowKeysSample();
app.exec();
}
}
1:UP, 2:RIGHT, 3:UP, RIGHT, 4:DOWN, 5:UP, DOWN, 15:UP, RIGHT, DOWN, LEFT,
このプログラムでは、例えば、「UPの矢印キーが押下されているときは1」「UPとRIGHTの矢印キーが同時に押下されているときは3」「全部が押下されているときは15」となっていて、どのキーが押されているかが、int値から分かります。「UP」「RIGHT」といった定数がint値の各ビットと対応付けされているので、int値の対応するビットが0なのか、1なのかで、押下を判定できるのです。
ビット和操作を列挙型で実現できる「java.util.EnumSet」クラス
同様なプログラムを、int enumパターンではなく列挙型でできないでしょうか。実は、Javaでは「java.util.EnumSet」クラスが用意されていて、実現可能です。
package sample21;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
public class EnumArrowKeysSample {
enum ArrowKeys { UP, RIGHT, DOWN, LEFT }
public void exec() {
List<EnumSet<ArrowKeys>> keys = new ArrayList<EnumSet<ArrowKeys>>();
keys.add(EnumSet.of(ArrowKeys.UP));
keys.add(EnumSet.of(ArrowKeys.RIGHT));
keys.add(EnumSet.of(ArrowKeys.UP, ArrowKeys.RIGHT));
keys.add(EnumSet.of(ArrowKeys.DOWN));
keys.add(EnumSet.of(ArrowKeys.UP, ArrowKeys.DOWN));
keys.add(EnumSet.allOf(ArrowKeys.class));
for (EnumSet<ArrowKeys> e : keys) {
System.out.print(e + ":");
if (e.contains(ArrowKeys.UP)) {
System.out.print("UP, ");
}
if (e.contains(ArrowKeys.RIGHT)) {
System.out.print("RIGHT, ");
}
if (e.contains(ArrowKeys.DOWN)) {
System.out.print("DOWN, ");
}
if (e.contains(ArrowKeys.LEFT)) {
System.out.print("LEFT, ");
}
System.out.println("");
}
}
public static void main(String[] args) {
EnumArrowKeysSample app = new EnumArrowKeysSample();
app.exec();
}
}
[UP]:UP, [RIGHT]:RIGHT, [UP, RIGHT]:UP, RIGHT, [DOWN]:DOWN, [UP, DOWN]:UP, DOWN, [UP, RIGHT, DOWN, LEFT]:UP, RIGHT, DOWN, LEFT,
このプログラムでは、EnumSet型のオブジェクトで矢印キーの押下を表現しています。
例えば、UPの矢印キーが押下されているときは「EnumSet.of(ArrowKeys.UP)」、UPとRIGHTの矢印キーが同時に押下されているときは「EnumSet.of(ArrowKeys.UP, ArrowKeys.RIGHT)」、全部が押下されているときは「EnumSet.allOf(ArrowKeys.class)」、となっています。
次回は、Java 5からの肝「アノテーション」
ある値を列挙してプログラムで利用したい場合は、Javaでは列挙型を使えばいいことが理解できたでしょうか。Javaのバージョンによっては(5よりも前の場合)列挙型が使えませんから、その場合はタイプセーフenumパターンを使います。
また、サンプルプログラムでちょっとした値を列挙したい場合や、列挙型を使うまでもない場合は、int enumパターンが使えます。作成したいプログラム、Javaのバージョンといったプログラミング環境に合わせて、どれを使うか決めるといいでしょう。
本記事では、列挙型の基本的な使い方について説明しましたが、インターフェイスを実装したり、独自のメソッドやフィールドを宣言して使う方法もあります。Javaの列挙型はいろいろな場面で利用できますから、興味がある読者は、enumについてさらに調べてみてください。
次回は、Java 5からの肝といえる「アノテーション」について説明する予定です。今回作ったサンプルのソースコードはこちらからダウンロードできます。
筆者紹介
小山博史(こやま ひろし)
情報家電、コンピュータと教育の研究に従事する傍ら、オープンソースソフトウェア、Java技術の普及のための活動を行っている。長野県の地域コミュニティである、SSS(G)やbugs(J)の活動へも参加している。
著書に「基礎Java」(インプレス)、共著に「Javaコレクションフレームワーク」(ソフトバンククリエイティブ)、そのほかに雑誌執筆多数。
- Javaの例外処理で知らないと損する7つのテクニック
- プログラマの宿命! 例外とエラー処理を理解する
- いまさら聞けない「Javadoc」と「アノテーション」入門
- 7ステップで理解するJavaでの列挙型/enum使用法
- 拡張for文の真の実力を知り、反復処理を使いこなせ
- キュー構造をJavaで実装してジェネリック型を理解する
- 強く型付けされているJavaの理解に必修の“型変換”
- あなたの知らない、4つのマニアックなJava文法
- “ネスト”した型で始める軽量Javaプログラミング!?
- Javaは「抽象クラス」で実装を上手に再利用できる
- 再利用性の高いクラス作成に重要な“アクセス制御”
- “コンストラクタ”と初期化、本当に理解できてる?
- 継承やオーバーライドで簡単にクラスを“拡張”しよう
- 「static」でクラス共有の変数・メソッドを使いこなせ!
- Javaの実案件に必須のパッケージとインポートを知る
- プログラムを「変更」しやすくする“インターフェイス”
- Javaの参照型を文字列操作で理解して文法を総復習
- クラスの振る舞いを表すJavaの“メソッド”とは?
- 複雑なデータを表現できるクラスやフィールドって?
- データ集合を扱うのに便利なJavaの配列と拡張for文
- プログラミングの真骨頂! Javaで“反復処理”を覚える
- プログラミングの醍醐味! Javaで“条件式”を理解する
- Javaで一から理解するプログラムの変数と演算子
- Eclipse 3.4で超簡単Javaプログラミング基礎入門
Copyright © ITmedia, Inc. All Rights Reserved.