gpt4 book ai didi

java - 枚举 : Why? 什么时候?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:58:31 26 4
gpt4 key购买 nike

我是一名即将毕业的计算机科学专业的学生,​​在我的编码生涯中,我发现很少有使用枚举的实例,除了典型的情况,例如代表一副标准纸牌的面孔。

您知道在日常编码中使用枚举的任何巧妙方法吗?

为什么枚举如此重要,在什么情况下应该能够确定构建枚举是最好的方法?

最佳答案

这些是 enum 的主要论据, EnumMap , 和 EnumSet通过简短的例子。

枚举的情况

从 Java 6 开始,java.util.Calendar是一个杂乱类的示例,它可以从使用 enum(以及其他改进)中获益良多。

当前 Calendar 定义了以下常量 ( among many others ):

// int constant antipattern from java.util.Calendar
public static final int JANUARY = 0;
public static final int FEBRUARY = 1;
...
public static final int SUNDAY = 1;
public static final int MONDAY = 2;
...

这些都是int,尽管它们显然代表不同的概念实体。

以下是一些严重的后果:

  • 它很脆;必须注意在需要时分配不同的编号。
    • 如果我们错误地设置了 MONDAY = 0;SUNDAY = 0;,那么我们有 MONDAY == SUNDAY
  • 没有命名空间,也没有类型安全,因为一切都只是一个 int:
    • 我们可以setMonth(JANUARY),但我们也可以setMonth(THURSDAY)setMonth(42)
    • 谁知道是什么set(int,int,int,int,int,int) (一个真正的方法!)确实如此!

相比之下,我们可以有这样的东西:

// Hypothetical enums for a Calendar library
enum Month {
JANUARY, FEBRUARY, ...
}
enum DayOfWeek {
SUNDAY, MONDAY, ...
}

现在我们再也不用担心 MONDAY == SUNDAY(它永远不会发生!),因为 MonthDayOfWeek 是不同的类型,setMonth(MONDAY) 无法编译。

此外,这里还有一些前后对比代码:

// BEFORE with int constants
for (int month = JANUARY; month <= DECEMBER; month++) {
...
}

我们在这里做出各种假设,例如JANUARY + 1 == FEBRUARY 等。另一方面,enum 的对应物更简洁、更具可读性,并且做出更少的假设(因此出现错误的机会更少) ):

// AFTER with enum
for (Month month : Month.values()) {
...
}

实例字段的情况

在 Java 中,enum 是一个具有许多特殊属性的 class,但仍然是 class,允许您定义实例方法和字段如有必要。

考虑以下示例:

// BEFORE: with int constants
public static final int NORTH = 0;
public static final int EAST = 1;
public static final int SOUTH = 2;
public static final int WEST = 3;

public static int degreeFor(int direction) {
return direction * 90; // quite an assumption!
// must be kept in-sync with the int constants!
}

//...
for (int dir = NORTH; dir <= WEST; dir++) {
... degreeFor(dir) ...
}

另一方面,使用 enum 你可以这样写:

enum Direction {
NORTH(0), EAST(90), SOUTH(180), WEST(270);
// so obvious! so easy to read! so easy to write! so easy to maintain!

private final int degree;
Direction(int degree) { this.degree = degree; }
public int getDegree() { return degree; }
}

//...
for (Direction dir : Direction.values()) {
... dir.getDegree() ...
}

实例方法的案例

考虑以下示例:

static int apply(int op1, int op2, int operator) {
switch (operator) {
case PLUS : return op1 + op2;
case MINUS : return op1 - op2;
case ...
default: throw new IllegalArgumentException("Unknown operator!");
}
}

如前例所示,Java 中的enum 可以有实例方法,但不仅如此,每个常量也可以有自己特定的@Override。这显示在以下代码中:

enum Operator {
PLUS { int apply(int op1, int op2) { return op1 + op2; } },
MINUS { int apply(int op1, int op2) { return op1 - op2; } },
...
;
abstract int apply(int op1, int op2);
}

EnumMap 的情况

引用自Effective Java 2nd Edition:

Never derive a value associated with an enum from its ordinal(); store it in an instance field instead. (Item 31: Use instance fields instead of ordinals) It is rarely appropriate to use ordinals to index arrays: use EnumMap instead. The general principle is that application programmers should rarely, if ever, use Enum.ordinal. (Item 33: Use EnumMap instead of ordinal indexing)

基本上像以前一样你可能有这样的东西:

// BEFORE, with int constants and array indexing
Employee[] employeeOfTheMonth = ...

employeeOfTheMonth[JANUARY] = jamesBond;

现在你可以:

// AFTER, with enum and EnumMap
Map<Month, Employee> employeeOfTheMonth = ...

employeeOfTheMonth.put(Month.JANUARY, jamesBond);

EnumSet 的情况

两个 int 常量的幂经常被使用,例如在 C++ 中表示位集。这依赖于 bitwise operations .示例可能如下所示:

public static final int BUTTON_A = 1;
public static final int BUTTON_B = 2;
public static final int BUTTON_X = 4;
public static final int BUTTON_Y = 8;

int buttonState = BUTTON_A | BUTTON_X; // A & X are pressed!

if ((buttonState & BUTTON_B) != 0) { // B is pressed...
...
}

使用 enumEnumSet,这看起来像这样:

enum Button {
A, B, X, Y;
}

Set<Button> buttonState = EnumSet.of(Button.A, Button.X); // A & X are pressed!

if (buttonState.contains(Button.B)) { // B is pressed...
...
}

引用资料

另见

  • Effective Java 第二版
    • 条款 30:使用 enum 而不是 int 常量
    • 条款 31:使用实例字段而不是序数
    • 项目 32:使用 EnumSet而不是位域
    • 项目 33:使用 EnumMap而不是顺序索引

相关问题

关于java - 枚举 : Why? 什么时候?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3363120/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com