@blog.justoneplanet.info

日々勉強

Javaの列挙型

以下のようにしてenumを宣言し、定数を列挙することができる。

enum Suit {CLUBS, DIAMONDS, HEARTS, SPADES}

staticフィールドとして考える。以下のようにしてアクセスすることができる。

Suit.HEARTS

名前付き整数定数

一見すると以下のようなコードに対してenumのメリットがわかりにくい。

class Car {
    static final int TYPE_SEDAN = 1;
    static final int TYPE_MINI  = 2;

    static final int COLOR_RED  = 1;
    static final int COLOR_BLUE = 2;

    Car(int type, int color);
}

しかし致命的な欠点があり、以下のようなコードもエラーとならない。

Car car = new Car(Car.COLOR_RED, Car.TYPE_SEDAN);

enum

以下のようにして定義する。

class Car {
    static enum Type{SEDAN, MINI};
    static enum Color{RED, BLUE};
    Car(Type type, Color color);
}

型安全であるので以下のようにするとエラーとなる。

Car car = new Car(Car.Color.RED, Car.Type.SEDAN);

PHPにはない(よね?)ので便利である。

■宣言

最後のenum定数の後にカンマを書いておくことはできる。

enum Type {
    SEDAN,
    MINI,
}

PHPの配列定義と同じで便利である。但し、enum定数以外のものを宣言する場合はセミコロンで終了させる必要がある。

static enum Type{
    SEDAN,
    MINI;
    public static int getSize(){return 4;};
};

メソッド

全てのenum型Eはコンパイラーによって以下のstaticメソッドを持つ。

public static E[] values()
宣言された順序で各enum定数を含む配列を返す
public static E valueOf(String name)
指定されたnameを持つenum定数を返す。存在しない時はIllegalArgumentExceptionをthrowする

また以下のようなメソッドがある。

public final int ordinal()
enum定数の順序値を返す(ChessPiece.PAWN.ordinal())
public final Class getDeclaringClass()
enum定数のenum型を表しているClassオブジェクトを返す

■修飾子

以下の修飾子を付けることができる。

アノテーション
アクセス修飾子
static
全てのネストしたenumはstaticである。慣習として省略される
staticの浮動小数点(strictfp)

アクセス修飾子について

  • パッケージアクセス
  • public
ネストされている場合
  • private
  • protected
  • パッケージアクセス
  • public

■生成

以下のようにしてコンストラクタを持つことができる。

enum Type{
    SEDAN("sedan"),
    MINI("mini");
    
    String name;
    Type(String name){this.name = name;};
};

以下のようにアクセスすることができる。

String str = Type.SEDAN.name;// sedan
  • 全てのenumコンストラクタはprivateであるが慣習的に省略される
  • コンストラクタはスーパークラスのコンストラクタの呼び出しを明示することはできない
  • enumコンストラクタはenumの非定数staticフィールドを使用できない(定数ではないstaticフィールドの初期化はコンストラクタの実行後に実行される)

■用例

以下のようにして使うのが一般的である。

enum ChessPiece {
    PAWN, ROOK, BISHOP, KNIGHT, KING, QUEEN;
}
Set<Position> reachable(ChessPiece type, Position current) {
    if(type == ChessPiece.PAWN) {
        return pawnReachaable(current);
    }
    else if(type == ChessPiece.ROOK) {
        return rookReachaable(current);
    }
    else if(type == ChessPiece.QUEEN) {
        return queenReachaable(current);
    }
//...
    else {
        throw new Error("Unknow type");
    }
}

以下のように(値と処理をセットで)記述することで特定の値に対する処理を忘れることがない。

enum ChessPiece {
    PAWN {
        Set<Position> reachable(Position current) {
            return ChessRules.pawnReachable(current);
        }
    },
    ROOK {
        Set<Position> reachable(Position current) {
            return ChessRules.pawnReachable(current);
        }
    },
    QUEEN {
        Set<Position> reachable(Position current) {
            return ChessRules.pawnReachable(current);
        }
    };

    // enumが定義するメソッドの宣言
    abstract Set<Position> reachable(Position current);
}

各enum定数に対して定義されているクラスは実質的にエンクロージングenum型を継承している無名内部クラスである。staticメンバやコンストラクタを宣言することはできない。

ちなみにenum定数のコンストラクタが存在する場合は以下のようになる。

enum ChessPiece {
    PAWN("pawn") {
        Set<Position> reachable(Position current) {
            return ChessRules.pawnReachable(current);
        }
    },
    ROOK("rook") {
        Set<Position> reachable(Position current) {
            return ChessRules.pawnReachable(current);
        }
    },
    QUEEN("queen") {
        Set<Position> reachable(Position current) {
            return ChessRules.pawnReachable(current);
        }
    };

    // enumが定義するメソッドの宣言
    abstract Set<Position> reachable(Position current);
    String name;
    ChessPiece(String name){this.name = name;};
}

enumをサブクラス化できないので、enumが固有の振る舞いを持つenum定数を宣言している場合は、classをfinalにする時と同様に考慮が必要である。

コメントはまだありません»

No comments yet.

RSS feed for comments on this post.TrackBack URL

Leave a comment