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

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

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

案例为enum

从 Java 6 开始,java.util.Calendar这是一个杂乱无章的类的示例,它可以从使用中受益匪浅enum(以及其他改进)。

当前Calendar定义了以下常量(除其他外):

// 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(它永远不会发生!),而且因为Month和DayOfWeek是不同的类型,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!");

}

}

如前面的示例所示,enum在 Java 中可以有实例方法,但不仅如此,每个常量也可以有自己的特定@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的引述:

enum永远不要从其ordinal();派生与 an 关联的值。而是将其存储在实例字段中。(第 31 条:使用实例字段而不是序数)使用序数来索引数组很少合适:使用EnumMap代替。一般原则是应用程序程序员应该很少(如果有的话)使用Enum.ordinal. (第 33 项:使用EnumMap代替序数索引)

基本上和以前一样,你可能会有这样的事情:

// BEFORE, with int constants and array indexing

Employee[] employeeOfTheMonth = ...

employeeOfTheMonth[JANUARY] = jamesBond;

现在你可以拥有:

// AFTER, with enum and EnumMap

Map employeeOfTheMonth = ...

employeeOfTheMonth.put(Month.JANUARY, jamesBond);

案例为EnumSet

int例如在 C++ 中经常使用两个常数的幂来表示位集。这依赖于按位运算。一个示例可能如下所示:

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...

...

}

使用enumand EnumSet,这看起来像这样:

enum Button {

A, B, X, Y;

}

Set

🎈 相关推荐

金河田主机
365体育亚洲官方登录

金河田主机

📅 07-03 👀 7713
为什么有人数学特别好?浙大团队花了5年时间研究发现……
国际足联2030世界杯扩军至64队?亚洲名额或将增至12席!