Java 列举:为什么?什么时候
我是一名即将毕业的计算机科学专业的学生,在我的编码生涯中,我发现很少有使用枚举的例子,除了代表一副标准卡片的面这样的典型例子之外Java 列举:为什么?什么时候,java,enums,enumeration,Java,Enums,Enumeration,我是一名即将毕业的计算机科学专业的学生,在我的编码生涯中,我发现很少有使用枚举的例子,除了代表一副标准卡片的面这样的典型例子之外 你知道在日常编码中使用枚举的聪明方法吗 为什么枚举如此重要?在什么情况下,人们应该能够确定构建枚举是最好的方法?我想你说的是枚举,而不是枚举 枚举非常适合应用程序中可能使用“幻数字符串”或“幻数”的任何地方 最容易理解其用法的领域是文件访问。枚举中表示每个文件访问模式(读、写、附加)。如果您使用的是“神奇数字”,则可能会出现如下情况: public static cl
你知道在日常编码中使用枚举的聪明方法吗
为什么枚举如此重要?在什么情况下,人们应该能够确定构建枚举是最好的方法?我想你说的是枚举,而不是枚举 枚举非常适合应用程序中可能使用“幻数字符串”或“幻数”的任何地方 最容易理解其用法的领域是文件访问。枚举中表示每个文件访问模式(读、写、附加)。如果您使用的是“神奇数字”,则可能会出现如下情况:
public static class Constants
{
public static final int FILEMODE_READ = 1;
public static final int FILEMODE_WRITE = 2;
public static final int FILEMODE_APPEND = 3;
}
当您可以使用枚举更清楚、简洁地表达意图时:
public enum FileMode
{
Read,
Write,
Append
}
默认答案:所有Java开发人员都应该明确阅读。在Java 1.5之前,有一章介绍了enum您将定义为
String
/int
常量的内容,现在您应该定义为enum。例如,与其拥有:
public class StatusConstants {
public int ACTIVE = 1;
public int SUSPENDED = 2;
public int TEMPORARY_INACTIVE = 3;
public int NOT_CONFIRMED = 4;
}
您现在有了一个更安全、更友好的开发人员界面:
public enum Status {
ACTIVE, SUSPENDED, TEMPORARY_INACTIVE, NOT_CONFIRMED
}
任何具有多个选项的情况都是如此,如状态、街道类型(街道、街道、道路等)、用户访问级别(管理员、版主、普通用户)等
查看更多示例和解释。考虑一些简单的代码: 没有枚举:
int OPT_A_ON = 1;
int OPT_A_OFF = 0;
int OPT_B_ON = 1;
int OPT_B_OFF = 0;
SetOption(OPT_A_ON, OPT_B_OFF); // Declaration: SetOption(int, int)
看起来不错吧?除了SetOptions()需要先选择选项B,然后选择选项A。这将很好地通过编译器,但在运行时,会向后设置选项
现在,使用枚举:
enum OptA {On =1, Off = 0};
enum OptB {On =1, Off = 0};
SetOption(OptA.On, OptB.Off);// Declaration: SetOption(OptB, OptA)
现在我们犯同样的错误,但这次,由于枚举是不同的类型,编译器会发现错误
(注意:我不是一个真正的Java程序员,所以请原谅一些小的语法错误)枚举非常适合表示某事物的状态。我经常使用枚举,例如:
public enum PlayerState {
WALKING, STANDING, JUMPING...
}
枚举和派生类之间总是要保持平衡。举一个简单的例子,考虑一个<代码> CAT/COM>类。代码>猫有不同程度的敌意。因此,我们可以创建派生类HostileCat,
FriendlyCat
,等等。然而,也有不同类型的猫,狮子
,老虎
,等等。突然,我们有了一大堆猫
对象。因此,另一种解决方案是在Cat
类中提供枚举,这减少了派生类的数量和总体复杂性。正如Manuel Selva所建议的,阅读有效的Java第二版,但也阅读singleton部分使用enum是拥有干净的单例对象的最简单方法这些是的主要参数,通过简短的示例
enum
在Java6中,是一个凌乱类的示例,它可以从使用enum
(以及其他改进)中受益匪浅
当前,日历定义了以下常量():
这些都是int
,尽管它们显然代表不同的概念实体
以下是一些严重后果:
- 它很脆;需要时,必须注意分配不同的号码。
- 如果我们错误地设置了
MONDAY=0代码>,SUNDAY=0代码>,那么我们有周一==周日
- 没有名称空间,也没有类型安全性,因为所有内容都只是一个
int
:
- 我们可以
setMonth(一月)
,但我们也可以setMonth(周四)
或setMonth(42)
- 谁知道(真正的方法!)能做什么李>
相比之下,我们可以采用类似的方式:
// 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++) {
...
}
实例字段的情况
在Java中,enum
是一个具有许多特殊属性的类,但仍然是一个类,允许您在必要时定义实例方法和字段
考虑以下示例:
// 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) ...
}
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!");
}
}
实例方法的例子
考虑以下示例:
// 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) ...
}
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
这里引用了《有效Java第二版》中的一段话:
切勿从枚举中派生与枚举关联的值;而是将其存储在实例字段中。(第31项:使用实例字段而不是序数)使用序数索引数组很少合适:请改用EnumMap
。一般原则是应用程序程序员应该很少(如果有的话)使用Enum.ordinal
。(第33项:使用EnumMap
代替顺序索引)
基本上,与以前一样,您可能会遇到以下情况:
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() ...
}
// BEFORE, with int constants and array indexing
Employee[] employeeOfTheMonth = ...
employeeOfTheMonth[JANUARY] = jamesBond;
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 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...
...
}
现在您可以拥有:
// AFTER, with enum and EnumMap
Map<Month, Employee> employeeOfTheMonth = ...
employeeOfTheMonth.put(Month.JANUARY, jamesBond);
使用enum
和EnumSet
,可以看到如下情况:
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() ...
}
// BEFORE, with int constants and array indexing
Employee[] employeeOfTheMonth = ...
employeeOfTheMonth[JANUARY] = jamesBond;
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 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按钮{
A、 B,X,Y;
}
Set buttonState=EnumSet.of(Button.A,Button.X);//按下A&X键!
如果按下(buttonState.contains(Button.B)){//B。。。
...
}
工具书类
- --比较完整,有很多例子
另见
- 有效Java第二版
- 第30项:使用
enum
而不是int
常量
- 项目31:使用