我是一名即将毕业的计算机科学专业的学生,在我的整个编码生涯中,我发现很少使用枚举的实例,除了典型的情况(例如代表标准纸牌的面孔)外,还使用了枚举。
您是否知道在日常编码中使用枚举的任何巧妙方法?
为什么枚举如此重要,在什么情况下应该能够确定建立枚举是最佳方法?
这些是主要的论点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()
;
而是将其存储在实例字段中。( 第31项:使用实例字段代替序数
)使用序数为数组建立索引很少是合适的:使用EnumMap
替代。一般原则是,应用程序程序员应该很少使用(如果有的话)Enum.ordinal
。(
项目33:使用EnumMap
而不是顺序索引)
从本质上讲,您可能会像这样:
// 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
++中经常使用两个常数的幂来表示位集。这依赖于按位运算。一个例子可能看起来像这样:
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...
...
}
使用enum
和EnumSet
,可以看起来像这样:
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...
...
}
enum
而不是int
常量EnumSet
代替位字段EnumMap
而不是顺序索引我听到一些人建议在C++中使用枚举类,因为它们的类型安全。 但这到底意味着什么呢?
问题内容: 今天,我浏览了该站点上的一些问题,发现提到了 以单例模式使用的这种解决方案声称具有线程安全性的优点。 我从未使用过,并且使用Java编程已经有两年多了。显然,他们改变了很多。现在,他们甚至在自己内部提供了对OOP的全面支持。 现在为什么要在日常编程中使用枚举?为什么? 问题答案: 当变量(尤其是方法参数)只能从一小部分可能的值中取出一个时,应始终使用枚举。例如类型常量(合同状态:“永久
问题内容: 在Java 5及更高版本中,您具有foreach循环,该循环可以神奇地实现任何实现的对象: 但是,仍然没有实现,这意味着要迭代一个,您必须执行以下操作: 有谁知道为什么仍然不执行? 编辑: 为澄清起见,我不是在谈论枚举的语言概念,而是在Java API中称为“ 枚举 ” 的Java特定类。 问题答案: 枚举没有被修改为支持Iterable,因为它是一个接口,而不是一个具体的类(例如Ve
问题内容: 我刚刚发现Java允许枚举实现接口。有什么好的用例? 问题答案: 枚举不仅仅代表被动集(例如颜色)。他们可以代表与功能更复杂的对象,所以你可能想进一步功能添加到这些是那么-例如,你可能如接口,等等。支持这些和组件。
问题内容: 我想知道为什么在Java语言中a 不能扩展。 我不是在谈论一个延伸的(这不能做,因为Java没有多重继承,而Š隐含延长),但一类的以只添加额外的方法,而不是额外的枚举值。 就像是: 要这样使用: 因此,有人可以对此限制提供理由(或将我指向正确的JLS部分)吗? 问题答案: 我认为 他们这样做 的答案来自以下问题: 在您的示例中,如何实例化MyClass?用户永远不会(通过)显式实例化枚
问题内容: 如果语言设计者仅使用Enum 会对语言产生怎样的影响? 现在唯一的区别是有人会写 A扩展 但由于Java中不允许扩展枚举,因此仍然是非法的。我也在考虑为jvm提供一个字节码,该字节码将smth定义为扩展枚举-但是泛型不会受到影响,因为它们都被删除了。 那么,声明的重点是什么? 谢谢! 编辑 为简单起见,让我们来看一个例子: 这个类结构有什么问题?限制可以做什么? 问题答案: 这是一个普