5

特定のアクションを定義するために Enum を作成しました。外部 API に対するプログラミングIntegerこのアクションを表現するために を使用せざるを得ません。そのため、Enum に整数インスタンス フィールドを追加しました。ordinal()これは、 を使用した Enum 定数に依存したり、その順序に依存したりするのではなく、Joshua Bloch の効果的な Java と一致する必要がありますvalues()[index]

public enum Action {

    START(0),

    QUIT(1);

    public final int code;

    Protocol(int code) {
         this.code = code;
     }
}

API から整数値を取得し、whatそこから Enum 値を作成したいのですが、これを最も一般的な方法で実装するにはどうすればよいですか?

明らかに、そのようなファクトリ メソッドを追加しても機能しません。Enum をインスタンス化することはできません。

Action valueOf(int what) {
     return new Action(what);
}

もちろん、いつでも switch-case ステートメントを作成して、考えられるすべてのコードを追加し、適切な定数を返すことができます。しかし、同時に 2 つの場所でそれらを定義することは避けたいと思います。

4

3 に答える 3

5

あなたがそれらをたくさん持つつもりなら、あなたは:を使うことができますHashMap<Integer, Action>

private static final Map<Integer, Action> actions = new HashMap<>(values().size, 1);

static {
    for (Action action : values())
        actions.put(action.code, action);
}

// ...

public static Action valueOf(int what) {
    return actions.get(what);
}

これは、ルックアップがO(1)であるため、多数のAction値を使用する場合に役立ちます。HashMap

于 2013-01-18T18:12:15.480 に答える
1

コードが常にシーケンシャルで 0 から始まることが確実な場合、最も効率的なオプションは次のとおりです。

public enum Action {
    START(0),

    QUIT(1);

    public static final Action[] ACTIONS;
    static {
      ACTIONS = new Action[values().length];
      for(Action a : values()) {
        ACTIONS[a.code] = a;
      }
    }

    public final int code;

    Protocol(int code) {
         this.code = code;
     }
}
于 2013-01-18T18:26:39.770 に答える
0

私は個人的にそれをシンプルに保ち(YAGNI)、序数の値を使用します

  • 外部コードがその実装の詳細を認識せず、それに依存しないように、ロジックを列挙型内に保持します
  • 何かが壊れた場合(つまり、数値が0から始まらない場合、または増分でない場合)に失敗するテストがあることを確認します

列挙型コード:

public enum Action {

    START(0),
    QUIT(1);
    private final int code;

    Action(int code) {
        this.code = code;
    }

    public int getCode() {
        return code;
    }

    public static Action of(int code) {
        try {
            return Action.values()[code];
        } catch (IndexOutOfBoundsException e) {
            throw new IllegalArgumentException("not a valid code: " + code);
        }
    }
}

テスト

@Test
public testActionEnumOrder() {
    int i = 0;
    for (Action a : Action.values()) {
        assertEquals(a.getCode(), i++);
    }
}

たとえばに変更QUIT(1)するQUIT(2)と、テストは失敗します。その場合は、HashMapまたはルックアップループを使用できます。

于 2013-01-18T18:45:08.560 に答える